From 7eaceaccab5f40bbfda044629a6298616aeaed50 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 10 Mar 2011 08:52:07 +0100 Subject: block: remove per-queue plugging Code has been converted over to the new explicit on-stack plugging, and delay users have been converted to use the new API for that. So lets kill off the old plugging along with aops->sync_page(). Signed-off-by: Jens Axboe --- fs/cifs/file.c | 30 ------------------------------ 1 file changed, 30 deletions(-) (limited to 'fs/cifs/file.c') diff --git a/fs/cifs/file.c b/fs/cifs/file.c index e964b1cd5dd0..c27d236738fc 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1569,34 +1569,6 @@ int cifs_fsync(struct file *file, int datasync) return rc; } -/* static void cifs_sync_page(struct page *page) -{ - struct address_space *mapping; - struct inode *inode; - unsigned long index = page->index; - unsigned int rpages = 0; - int rc = 0; - - cFYI(1, "sync page %p", page); - mapping = page->mapping; - if (!mapping) - return 0; - inode = mapping->host; - if (!inode) - return; */ - -/* fill in rpages then - result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */ - -/* cFYI(1, "rpages is %d for sync page of Index %ld", rpages, index); - -#if 0 - if (rc < 0) - return rc; - return 0; -#endif -} */ - /* * As file closes, flush all cached write data for this inode checking * for write behind errors. @@ -2510,7 +2482,6 @@ const struct address_space_operations cifs_addr_ops = { .set_page_dirty = __set_page_dirty_nobuffers, .releasepage = cifs_release_page, .invalidatepage = cifs_invalidate_page, - /* .sync_page = cifs_sync_page, */ /* .direct_IO = */ }; @@ -2528,6 +2499,5 @@ const struct address_space_operations cifs_addr_ops_smallbuf = { .set_page_dirty = __set_page_dirty_nobuffers, .releasepage = cifs_release_page, .invalidatepage = cifs_invalidate_page, - /* .sync_page = cifs_sync_page, */ /* .direct_IO = */ }; -- cgit v1.2.3 From 7797069305d13252fd66cf722aa8f2cbeb3c95cd Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 5 Apr 2011 16:23:47 -0700 Subject: cifs: check for private_data before trying to put it cifs_close doesn't check that the filp->private_data is non-NULL before trying to put it. That can cause an oops in certain error conditions that can occur on open or lookup before the private_data is set. Reported-by: Ben Greear CC: Stable Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/file.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'fs/cifs/file.c') diff --git a/fs/cifs/file.c b/fs/cifs/file.c index c27d236738fc..5ae061c4ca25 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -575,8 +575,10 @@ reopen_error_exit: int cifs_close(struct inode *inode, struct file *file) { - cifsFileInfo_put(file->private_data); - file->private_data = NULL; + if (file->private_data != NULL) { + cifsFileInfo_put(file->private_data); + file->private_data = NULL; + } /* return code from the ->release op is always ignored */ return 0; -- cgit v1.2.3 From bdf1b03e093bdbc571f404e751c7b0e2dca412ea Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 22 Feb 2011 20:17:19 -0500 Subject: cifs: replace /proc/fs/cifs/Experimental with a module parm This flag currently only affects whether we allow "zero-copy" writes with signing enabled. Typically we map pages in the pagecache directly into the write request. If signing is enabled however and the contents of the page change after the signature is calculated but before the write is sent then the signature will be wrong. Servers typically respond to this by closing down the socket. Still, this can provide a performance benefit so the "Experimental" flag was overloaded to allow this. That's really not a good place for this option however since it's not clear what that flag does. Move that flag instead to a new module parameter that better describes its purpose. That's also better since it can be set at module insertion time by configuring modprobe.d. Reviewed-by: Suresh Jayaraman Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/README | 16 ---------------- fs/cifs/cifs_debug.c | 43 ------------------------------------------- fs/cifs/cifsfs.c | 5 ++++- fs/cifs/cifsglob.h | 2 +- fs/cifs/file.c | 4 ++-- 5 files changed, 7 insertions(+), 63 deletions(-) (limited to 'fs/cifs/file.c') diff --git a/fs/cifs/README b/fs/cifs/README index fe1683590828..74ab165fc646 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -685,22 +685,6 @@ 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 directory change - notification code). When set to 2 enables - an additional experimental feature, "raw ntlmssp" - session establishment support (which allows - specifying "sec=ntlmssp" on mount). The Linux cifs - module will use ntlmv2 authentication encapsulated - in "raw ntlmssp" (not using SPNEGO) when - "sec=ntlmssp" is specified on mount. - This support also requires building cifs with - the CONFIG_CIFS_EXPERIMENTAL configuration flag. 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 diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 65829d32128c..30d01bc90855 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -423,7 +423,6 @@ static const struct file_operations cifs_lookup_cache_proc_fops; static const struct file_operations traceSMB_proc_fops; static const struct file_operations cifs_multiuser_mount_proc_fops; static const struct file_operations cifs_security_flags_proc_fops; -static const struct file_operations cifs_experimental_proc_fops; static const struct file_operations cifs_linux_ext_proc_fops; void @@ -441,8 +440,6 @@ cifs_proc_init(void) proc_create("cifsFYI", 0, proc_fs_cifs, &cifsFYI_proc_fops); proc_create("traceSMB", 0, proc_fs_cifs, &traceSMB_proc_fops); proc_create("OplockEnabled", 0, proc_fs_cifs, &cifs_oplock_proc_fops); - proc_create("Experimental", 0, proc_fs_cifs, - &cifs_experimental_proc_fops); proc_create("LinuxExtensionsEnabled", 0, proc_fs_cifs, &cifs_linux_ext_proc_fops); proc_create("MultiuserMount", 0, proc_fs_cifs, @@ -469,7 +466,6 @@ cifs_proc_clean(void) remove_proc_entry("OplockEnabled", proc_fs_cifs); remove_proc_entry("SecurityFlags", proc_fs_cifs); remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs); - remove_proc_entry("Experimental", proc_fs_cifs); remove_proc_entry("LookupCacheEnabled", proc_fs_cifs); remove_proc_entry("fs/cifs", NULL); } @@ -550,45 +546,6 @@ static const struct file_operations cifs_oplock_proc_fops = { .write = cifs_oplock_proc_write, }; -static int cifs_experimental_proc_show(struct seq_file *m, void *v) -{ - seq_printf(m, "%d\n", experimEnabled); - return 0; -} - -static int cifs_experimental_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, cifs_experimental_proc_show, NULL); -} - -static ssize_t cifs_experimental_proc_write(struct file *file, - const char __user *buffer, size_t count, loff_t *ppos) -{ - char c; - int rc; - - rc = get_user(c, buffer); - if (rc) - return rc; - if (c == '0' || c == 'n' || c == 'N') - experimEnabled = 0; - else if (c == '1' || c == 'y' || c == 'Y') - experimEnabled = 1; - else if (c == '2') - experimEnabled = 2; - - return count; -} - -static const struct file_operations cifs_experimental_proc_fops = { - .owner = THIS_MODULE, - .open = cifs_experimental_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .write = cifs_experimental_proc_write, -}; - static int cifs_linux_ext_proc_show(struct seq_file *m, void *v) { seq_printf(m, "%d\n", linuxExtEnabled); diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index f2970136d17d..41c78e8fc591 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -53,7 +53,6 @@ int cifsFYI = 0; int cifsERROR = 1; int traceSMB = 0; unsigned int oplockEnabled = 1; -unsigned int experimEnabled = 0; unsigned int linuxExtEnabled = 1; unsigned int lookupCacheEnabled = 1; unsigned int multiuser_mount = 0; @@ -82,6 +81,10 @@ module_param(echo_retries, ushort, 0644); MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and " "reconnecting server. Default: 5. 0 means " "never reconnect."); +bool sign_zero_copy; /* globals init to false automatically */ +module_param(sign_zero_copy, bool, 0644); +MODULE_PARM_DESC(sign_zero_copy, "Don't copy pages on write with signing " + "enabled. Default: N"); extern mempool_t *cifs_sm_req_poolp; extern mempool_t *cifs_req_poolp; extern mempool_t *cifs_mid_poolp; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 17afb0fbcaed..10e4afe54e22 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -817,7 +817,6 @@ GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions have the uid/password or Kerberos credential or equivalent for current user */ GLOBAL_EXTERN unsigned int oplockEnabled; -GLOBAL_EXTERN unsigned int experimEnabled; GLOBAL_EXTERN unsigned int lookupCacheEnabled; GLOBAL_EXTERN unsigned int global_secflags; /* if on, session setup sent with more secure ntlmssp2 challenge/resp */ @@ -827,6 +826,7 @@ GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ +GLOBAL_EXTERN bool sign_zero_copy; /* don't copy written pages with signing */ /* reconnect after this many failed echo attempts */ GLOBAL_EXTERN unsigned short echo_retries; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 5ae061c4ca25..e2d7b6bada6f 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -981,7 +981,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, if (rc != 0) break; } - if (experimEnabled || (pTcon->ses->server && + if (sign_zero_copy || (pTcon->ses->server && ((pTcon->ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0))) { @@ -1242,7 +1242,7 @@ static int cifs_writepages(struct address_space *mapping, } tcon = tlink_tcon(open_file->tlink); - if (!experimEnabled && tcon->ses->server->secMode & + if (!sign_zero_copy && tcon->ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { cifsFileInfo_put(open_file); kfree(iov); -- cgit v1.2.3 From ca83ce3d5b9ad321ee24f5870a77f0b21ac5a5de Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 12 Apr 2011 09:13:44 -0400 Subject: cifs: don't allow mmap'ed pages to be dirtied while under writeback (try #3) This is more or less the same patch as before, but with some merge conflicts fixed up. If a process has a dirty page mapped into its page tables, then it has the ability to change it while the client is trying to write the data out to the server. If that happens after the signature has been calculated then that signature will then be wrong, and the server will likely reset the TCP connection. This patch adds a page_mkwrite handler for CIFS that simply takes the page lock. Because the page lock is held over the life of writepage and writepages, this prevents the page from becoming writeable until the write call has completed. With this, we can also remove the "sign_zero_copy" module option and always inline the pages when writing. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 4 ---- fs/cifs/cifsglob.h | 1 - fs/cifs/file.c | 64 ++++++++++++++++++++++++++++-------------------------- 3 files changed, 33 insertions(+), 36 deletions(-) (limited to 'fs/cifs/file.c') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index e3352a1ac479..5c412b33cd7c 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -81,10 +81,6 @@ module_param(echo_retries, ushort, 0644); MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and " "reconnecting server. Default: 5. 0 means " "never reconnect."); -bool sign_zero_copy; /* globals init to false automatically */ -module_param(sign_zero_copy, bool, 0644); -MODULE_PARM_DESC(sign_zero_copy, "Don't copy pages on write with signing " - "enabled. Default: N"); extern mempool_t *cifs_sm_req_poolp; extern mempool_t *cifs_req_poolp; extern mempool_t *cifs_mid_poolp; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index ddb359906708..a5d1106fcbde 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -826,7 +826,6 @@ GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ -GLOBAL_EXTERN bool sign_zero_copy; /* don't copy written pages with signing */ /* reconnect after this many failed echo attempts */ GLOBAL_EXTERN unsigned short echo_retries; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index e2d7b6bada6f..faf59529e847 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -972,6 +972,9 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, total_written += bytes_written) { rc = -EAGAIN; while (rc == -EAGAIN) { + struct kvec iov[2]; + unsigned int len; + if (open_file->invalidHandle) { /* we could deadlock if we called filemap_fdatawait from here so tell @@ -981,31 +984,14 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, if (rc != 0) break; } - if (sign_zero_copy || (pTcon->ses->server && - ((pTcon->ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - == 0))) { - struct kvec iov[2]; - unsigned int len; - - len = min((size_t)cifs_sb->wsize, - write_size - total_written); - /* iov[0] is reserved for smb header */ - iov[1].iov_base = (char *)write_data + - total_written; - iov[1].iov_len = len; - rc = CIFSSMBWrite2(xid, pTcon, - open_file->netfid, len, - *poffset, &bytes_written, - iov, 1, 0); - } else - 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, 0); + + len = min((size_t)cifs_sb->wsize, + write_size - total_written); + /* iov[0] is reserved for smb header */ + iov[1].iov_base = (char *)write_data + total_written; + iov[1].iov_len = len; + rc = CIFSSMBWrite2(xid, pTcon, open_file->netfid, len, + *poffset, &bytes_written, iov, 1, 0); } if (rc || (bytes_written == 0)) { if (total_written) @@ -1242,12 +1228,6 @@ static int cifs_writepages(struct address_space *mapping, } tcon = tlink_tcon(open_file->tlink); - if (!sign_zero_copy && tcon->ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { - cifsFileInfo_put(open_file); - kfree(iov); - return generic_writepages(mapping, wbc); - } cifsFileInfo_put(open_file); xid = GetXid(); @@ -1982,6 +1962,24 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, return total_read; } +/* + * If the page is mmap'ed into a process' page tables, then we need to make + * sure that it doesn't change while being written back. + */ +static int +cifs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct page *page = vmf->page; + + lock_page(page); + return VM_FAULT_LOCKED; +} + +static struct vm_operations_struct cifs_file_vm_ops = { + .fault = filemap_fault, + .page_mkwrite = cifs_page_mkwrite, +}; + int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma) { int rc, xid; @@ -1993,6 +1991,8 @@ int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma) cifs_invalidate_mapping(inode); rc = generic_file_mmap(file, vma); + if (rc == 0) + vma->vm_ops = &cifs_file_vm_ops; FreeXid(xid); return rc; } @@ -2009,6 +2009,8 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) return rc; } rc = generic_file_mmap(file, vma); + if (rc == 0) + vma->vm_ops = &cifs_file_vm_ops; FreeXid(xid); return rc; } -- cgit v1.2.3