Loading fs/cifs/file.c +184 −7 Original line number Diff line number Diff line Loading @@ -21,11 +21,14 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/fs.h> #include <linux/backing-dev.h> #include <linux/stat.h> #include <linux/fcntl.h> #include <linux/mpage.h> #include <linux/pagemap.h> #include <linux/pagevec.h> #include <linux/smp_lock.h> #include <linux/writeback.h> #include <asm/div64.h> #include "cifsfs.h" #include "cifspdu.h" Loading Loading @@ -916,6 +919,16 @@ static struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) ((open_file->pfile->f_flags & O_RDWR) || (open_file->pfile->f_flags & O_WRONLY))) { read_unlock(&GlobalSMBSeslock); if(open_file->invalidHandle) { rc = cifs_reopen_file(cifs_inode->vfs_inode, open_file->pfile, FALSE); /* if it fails, try another handle - might be */ /* dangerous to hold up writepages with retry */ if(rc) { read_lock(&GlobalSMBSeslock); continue; } } return open_file; } } Loading Loading @@ -982,20 +995,181 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) return rc; } #if 0 #ifdef CONFIG_CIFS_EXPERIMENTAL static int cifs_writepages(struct address_space *mapping, struct writeback_control *wbc) { int rc = -EFAULT; struct backing_dev_info *bdi = mapping->backing_dev_info; unsigned int bytes_to_write; unsigned int bytes_written; struct cifs_sb_info *cifs_sb; int done = 0; pgoff_t end = -1; pgoff_t index; int is_range = 0; struct kvec iov[32]; int n_iov = 0; pgoff_t next; int nr_pages; __u64 offset = 0; struct cifsFileInfo *open_file = NULL; struct page *page; struct pagevec pvec; int rc = 0; int scanned = 0; int xid; cifs_sb = CIFS_SB(mapping->host->i_sb); /* * If wsize is smaller that the page cache size, default to writing * one page at a time via cifs_writepage */ if (cifs_sb->wsize < PAGE_CACHE_SIZE) return generic_writepages(mapping, wbc); /* * BB: Is this meaningful for a non-block-device file system? * If it is, we should test it again after we do I/O */ if (wbc->nonblocking && bdi_write_congested(bdi)) { wbc->encountered_congestion = 1; return 0; } xid = GetXid(); /* Find contiguous pages then iterate through repeating call 16K write then Setpageuptodate or if LARGE_WRITE_X support then send larger writes via kevec so as to eliminate a memcpy */ pagevec_init(&pvec, 0); if (wbc->sync_mode == WB_SYNC_NONE) index = mapping->writeback_index; /* Start from prev offset */ else { index = 0; scanned = 1; } if (wbc->start || wbc->end) { index = wbc->start >> PAGE_CACHE_SHIFT; end = wbc->end >> PAGE_CACHE_SHIFT; is_range = 1; scanned = 1; } retry: while (!done && (index <= end) && (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, PAGECACHE_TAG_DIRTY, min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) { int first; unsigned int i; if (!open_file) { open_file = find_writable_file(CIFS_I(mapping->host)); if (!open_file) { pagevec_release(&pvec); cERROR(1, ("No writable handles for inode")); return -EIO; } } first = -1; next = 0; n_iov = 0; bytes_to_write = 0; for (i = 0; i < nr_pages; i++) { page = pvec.pages[i]; /* * At this point we hold neither mapping->tree_lock nor * lock on the page itself: the page may be truncated or * invalidated (changing page->mapping to NULL), or even * swizzled back from swapper_space to tmpfs file * mapping */ if (first < 0) lock_page(page); else if (TestSetPageLocked(page)) break; if (unlikely(page->mapping != mapping)) { unlock_page(page); break; } if (unlikely(is_range) && (page->index > end)) { done = 1; unlock_page(page); break; } if (next && (page->index != next)) { /* Not next consecutive page */ unlock_page(page); break; } if (wbc->sync_mode != WB_SYNC_NONE) wait_on_page_writeback(page); if (PageWriteback(page) || !test_clear_page_dirty(page)) { unlock_page(page); break; } /* * BB can we get rid of this? pages are held by pvec */ page_cache_get(page); /* reserve iov[0] for the smb header */ n_iov++; iov[n_iov].iov_base = kmap(page); iov[n_iov].iov_len = PAGE_CACHE_SIZE; bytes_to_write += PAGE_CACHE_SIZE; if (first < 0) { first = i; offset = page_offset(page); } next = page->index + 1; if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize) break; } if (n_iov) { rc = CIFSSMBWrite2(xid, cifs_sb->tcon, open_file->netfid, bytes_to_write, offset, &bytes_written, iov, n_iov, 1); if (rc || bytes_written < bytes_to_write) { cERROR(1,("CIFSSMBWrite2 returned %d, written = %x", rc, bytes_written)); set_bit(AS_EIO, &mapping->flags); SetPageError(page); } for (i = 0; i < n_iov; i++) { page = pvec.pages[first + i]; kunmap(page); unlock_page(page); page_cache_release(page); } if ((wbc->nr_to_write -= n_iov) <= 0) done = 1; index = next; } pagevec_release(&pvec); } if (!scanned && !done) { /* * We hit the last page and there is more work to be done: wrap * back to the start of the file */ scanned = 1; index = 0; goto retry; } if (!is_range) mapping->writeback_index = index; FreeXid(xid); return rc; } #endif Loading Loading @@ -1635,6 +1809,9 @@ struct address_space_operations cifs_addr_ops = { .readpage = cifs_readpage, .readpages = cifs_readpages, .writepage = cifs_writepage, #ifdef CONFIG_CIFS_EXPERIMENTAL .writepages = cifs_writepages, #endif .prepare_write = cifs_prepare_write, .commit_write = cifs_commit_write, .set_page_dirty = __set_page_dirty_nobuffers, Loading fs/cifs/transport.c +6 −4 Original line number Diff line number Diff line Loading @@ -395,7 +395,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, if (long_op == -1) goto cifs_no_response_exit2; else if (long_op == 2) /* writes past end of file can take loong time */ timeout = 300 * HZ; timeout = 180 * HZ; else if (long_op == 1) timeout = 45 * HZ; /* should be greater than servers oplock break timeout (about 43 seconds) */ Loading Loading @@ -431,7 +431,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, spin_unlock(&GlobalMid_Lock); receive_len = midQ->resp_buf->smb_buf_length; } else { cERROR(1,("No response buffer")); cERROR(1,("No response to cmd %d mid %d", midQ->command, midQ->mid)); if(midQ->midState == MID_REQUEST_SUBMITTED) { if(ses->server->tcpStatus == CifsExiting) rc = -EHOSTDOWN; Loading Loading @@ -646,7 +647,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, if (long_op == -1) goto cifs_no_response_exit; else if (long_op == 2) /* writes past end of file can take loong time */ timeout = 300 * HZ; timeout = 180 * HZ; else if (long_op == 1) timeout = 45 * HZ; /* should be greater than servers oplock break timeout (about 43 seconds) */ Loading Loading @@ -682,7 +683,8 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, spin_unlock(&GlobalMid_Lock); receive_len = midQ->resp_buf->smb_buf_length; } else { cERROR(1,("No response buffer")); cERROR(1,("No response for cmd %d mid %d", midQ->command, midQ->mid)); if(midQ->midState == MID_REQUEST_SUBMITTED) { if(ses->server->tcpStatus == CifsExiting) rc = -EHOSTDOWN; Loading Loading
fs/cifs/file.c +184 −7 Original line number Diff line number Diff line Loading @@ -21,11 +21,14 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/fs.h> #include <linux/backing-dev.h> #include <linux/stat.h> #include <linux/fcntl.h> #include <linux/mpage.h> #include <linux/pagemap.h> #include <linux/pagevec.h> #include <linux/smp_lock.h> #include <linux/writeback.h> #include <asm/div64.h> #include "cifsfs.h" #include "cifspdu.h" Loading Loading @@ -916,6 +919,16 @@ static struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) ((open_file->pfile->f_flags & O_RDWR) || (open_file->pfile->f_flags & O_WRONLY))) { read_unlock(&GlobalSMBSeslock); if(open_file->invalidHandle) { rc = cifs_reopen_file(cifs_inode->vfs_inode, open_file->pfile, FALSE); /* if it fails, try another handle - might be */ /* dangerous to hold up writepages with retry */ if(rc) { read_lock(&GlobalSMBSeslock); continue; } } return open_file; } } Loading Loading @@ -982,20 +995,181 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) return rc; } #if 0 #ifdef CONFIG_CIFS_EXPERIMENTAL static int cifs_writepages(struct address_space *mapping, struct writeback_control *wbc) { int rc = -EFAULT; struct backing_dev_info *bdi = mapping->backing_dev_info; unsigned int bytes_to_write; unsigned int bytes_written; struct cifs_sb_info *cifs_sb; int done = 0; pgoff_t end = -1; pgoff_t index; int is_range = 0; struct kvec iov[32]; int n_iov = 0; pgoff_t next; int nr_pages; __u64 offset = 0; struct cifsFileInfo *open_file = NULL; struct page *page; struct pagevec pvec; int rc = 0; int scanned = 0; int xid; cifs_sb = CIFS_SB(mapping->host->i_sb); /* * If wsize is smaller that the page cache size, default to writing * one page at a time via cifs_writepage */ if (cifs_sb->wsize < PAGE_CACHE_SIZE) return generic_writepages(mapping, wbc); /* * BB: Is this meaningful for a non-block-device file system? * If it is, we should test it again after we do I/O */ if (wbc->nonblocking && bdi_write_congested(bdi)) { wbc->encountered_congestion = 1; return 0; } xid = GetXid(); /* Find contiguous pages then iterate through repeating call 16K write then Setpageuptodate or if LARGE_WRITE_X support then send larger writes via kevec so as to eliminate a memcpy */ pagevec_init(&pvec, 0); if (wbc->sync_mode == WB_SYNC_NONE) index = mapping->writeback_index; /* Start from prev offset */ else { index = 0; scanned = 1; } if (wbc->start || wbc->end) { index = wbc->start >> PAGE_CACHE_SHIFT; end = wbc->end >> PAGE_CACHE_SHIFT; is_range = 1; scanned = 1; } retry: while (!done && (index <= end) && (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, PAGECACHE_TAG_DIRTY, min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) { int first; unsigned int i; if (!open_file) { open_file = find_writable_file(CIFS_I(mapping->host)); if (!open_file) { pagevec_release(&pvec); cERROR(1, ("No writable handles for inode")); return -EIO; } } first = -1; next = 0; n_iov = 0; bytes_to_write = 0; for (i = 0; i < nr_pages; i++) { page = pvec.pages[i]; /* * At this point we hold neither mapping->tree_lock nor * lock on the page itself: the page may be truncated or * invalidated (changing page->mapping to NULL), or even * swizzled back from swapper_space to tmpfs file * mapping */ if (first < 0) lock_page(page); else if (TestSetPageLocked(page)) break; if (unlikely(page->mapping != mapping)) { unlock_page(page); break; } if (unlikely(is_range) && (page->index > end)) { done = 1; unlock_page(page); break; } if (next && (page->index != next)) { /* Not next consecutive page */ unlock_page(page); break; } if (wbc->sync_mode != WB_SYNC_NONE) wait_on_page_writeback(page); if (PageWriteback(page) || !test_clear_page_dirty(page)) { unlock_page(page); break; } /* * BB can we get rid of this? pages are held by pvec */ page_cache_get(page); /* reserve iov[0] for the smb header */ n_iov++; iov[n_iov].iov_base = kmap(page); iov[n_iov].iov_len = PAGE_CACHE_SIZE; bytes_to_write += PAGE_CACHE_SIZE; if (first < 0) { first = i; offset = page_offset(page); } next = page->index + 1; if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize) break; } if (n_iov) { rc = CIFSSMBWrite2(xid, cifs_sb->tcon, open_file->netfid, bytes_to_write, offset, &bytes_written, iov, n_iov, 1); if (rc || bytes_written < bytes_to_write) { cERROR(1,("CIFSSMBWrite2 returned %d, written = %x", rc, bytes_written)); set_bit(AS_EIO, &mapping->flags); SetPageError(page); } for (i = 0; i < n_iov; i++) { page = pvec.pages[first + i]; kunmap(page); unlock_page(page); page_cache_release(page); } if ((wbc->nr_to_write -= n_iov) <= 0) done = 1; index = next; } pagevec_release(&pvec); } if (!scanned && !done) { /* * We hit the last page and there is more work to be done: wrap * back to the start of the file */ scanned = 1; index = 0; goto retry; } if (!is_range) mapping->writeback_index = index; FreeXid(xid); return rc; } #endif Loading Loading @@ -1635,6 +1809,9 @@ struct address_space_operations cifs_addr_ops = { .readpage = cifs_readpage, .readpages = cifs_readpages, .writepage = cifs_writepage, #ifdef CONFIG_CIFS_EXPERIMENTAL .writepages = cifs_writepages, #endif .prepare_write = cifs_prepare_write, .commit_write = cifs_commit_write, .set_page_dirty = __set_page_dirty_nobuffers, Loading
fs/cifs/transport.c +6 −4 Original line number Diff line number Diff line Loading @@ -395,7 +395,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, if (long_op == -1) goto cifs_no_response_exit2; else if (long_op == 2) /* writes past end of file can take loong time */ timeout = 300 * HZ; timeout = 180 * HZ; else if (long_op == 1) timeout = 45 * HZ; /* should be greater than servers oplock break timeout (about 43 seconds) */ Loading Loading @@ -431,7 +431,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, spin_unlock(&GlobalMid_Lock); receive_len = midQ->resp_buf->smb_buf_length; } else { cERROR(1,("No response buffer")); cERROR(1,("No response to cmd %d mid %d", midQ->command, midQ->mid)); if(midQ->midState == MID_REQUEST_SUBMITTED) { if(ses->server->tcpStatus == CifsExiting) rc = -EHOSTDOWN; Loading Loading @@ -646,7 +647,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, if (long_op == -1) goto cifs_no_response_exit; else if (long_op == 2) /* writes past end of file can take loong time */ timeout = 300 * HZ; timeout = 180 * HZ; else if (long_op == 1) timeout = 45 * HZ; /* should be greater than servers oplock break timeout (about 43 seconds) */ Loading Loading @@ -682,7 +683,8 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, spin_unlock(&GlobalMid_Lock); receive_len = midQ->resp_buf->smb_buf_length; } else { cERROR(1,("No response buffer")); cERROR(1,("No response for cmd %d mid %d", midQ->command, midQ->mid)); if(midQ->midState == MID_REQUEST_SUBMITTED) { if(ses->server->tcpStatus == CifsExiting) rc = -EHOSTDOWN; Loading