On Tue, 12 Apr 2011 14:07:04 +0400 Pavel Shilovsky <piastryyy@xxxxxxxxx> wrote: > 2011/4/2 Jeff Layton <jlayton@xxxxxxxxxx>: > > Have cifs_writepages issue asynchronous writes instead of waiting on > > each write call to complete before issuing another. This also allows us > > to return more quickly from writepages in the WB_SYNC_NONE case. It > > can just send out all of the I/Os and not wait around for the replies. > > > > In the WB_SYNC_ALL case, have it wait for all of the writes to complete > > after issuing them and return any errors that turn up from it. If those > > errors turn out to all be retryable (-EAGAIN), then retry the entire > > operation again. > > > > This also changes the page locking semantics a little bit. Instead of > > holding the page lock until the response is received, release it after > > doing the send. This will reduce contention for the page lock and should > > prevent processes that have the file mmap'ed from being blocked > > unnecessarily. > > > > Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx> > > --- > > Âfs/cifs/file.c | Â256 ++++++++++++++++++++++++++++++-------------------------- > > Â1 files changed, 136 insertions(+), 120 deletions(-) > > > > diff --git a/fs/cifs/file.c b/fs/cifs/file.c > > index da53246..dbdbe97 100644 > > --- a/fs/cifs/file.c > > +++ b/fs/cifs/file.c > > @@ -1087,32 +1087,69 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) > > Â Â Â Âreturn rc; > > Â} > > > > +/* > > + * walk a list of in progress async writes and wait for them to complete. > > + * Check the result code on each one. > > + * > > + * There's a clear heirarchy: 0 < EAGAIN < other errors > > + * > > + * If we get an EAGAIN return on a WB_SYNC_ALL writeout, then we need to > > + * go back and do the whole operation again. If we get other errors then > > + * the mapping already likely has AS_EIO or AS_ENOSPC set, so we can > > + * give up and just return an error. > > + */ > > +static int > > +cifs_wait_for_write_completion(struct address_space *mapping, > > + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â struct list_head *pending) > > +{ > > + Â Â Â int tmprc, rc = 0; > > + Â Â Â struct cifs_writedata *wdata; > > + > > + Â Â Â /* wait for writes to complete */ > > + Â Â Â for (;;) { > > + Â Â Â Â Â Â Â /* anything left on list? */ > > + Â Â Â Â Â Â Â spin_lock(&mapping->private_lock); > > + Â Â Â Â Â Â Â if (list_empty(pending)) { > > + Â Â Â Â Â Â Â Â Â Â Â spin_unlock(&mapping->private_lock); > > + Â Â Â Â Â Â Â Â Â Â Â break; > > + Â Â Â Â Â Â Â } > > + > > + Â Â Â Â Â Â Â /* dequeue an entry */ > > + Â Â Â Â Â Â Â wdata = list_first_entry(pending, struct cifs_writedata, > > + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Âpending); > > + Â Â Â Â Â Â Â list_del_init(&wdata->pending); > > + Â Â Â Â Â Â Â spin_unlock(&mapping->private_lock); > > + > > + Â Â Â Â Â Â Â /* wait for it to complete */ > > + Â Â Â Â Â Â Â tmprc = wait_for_completion_killable(&wdata->completion); > > + Â Â Â Â Â Â Â if (tmprc) > > + Â Â Â Â Â Â Â Â Â Â Â rc = tmprc; > > + > > + Â Â Â Â Â Â Â if (wdata->result == -EAGAIN) > > + Â Â Â Â Â Â Â Â Â Â Â rc = rc ? rc : wdata->result; > > + Â Â Â Â Â Â Â else if (wdata->result != 0) > > + Â Â Â Â Â Â Â Â Â Â Â rc = wdata->result; > > + > > + Â Â Â Â Â Â Â kref_put(&wdata->refcount, cifs_writedata_release); > > + Â Â Â } > > + > > + Â Â Â return rc; > > +} > > + > > Âstatic int cifs_writepages(struct address_space *mapping, > > Â Â Â Â Â Â Â Â Â Â Â Â Â struct writeback_control *wbc) > > Â{ > > - Â Â Â unsigned int bytes_to_write; > > - Â Â Â unsigned int bytes_written; > > - Â Â Â struct cifs_sb_info *cifs_sb; > > - Â Â Â int done = 0; > > + Â Â Â struct cifs_sb_info *cifs_sb = CIFS_SB(mapping->host->i_sb); > > + Â Â Â bool done = false, scanned = false, range_whole = false; > > Â Â Â Âpgoff_t end; > > Â Â Â Âpgoff_t index; > > - Â Â Â int range_whole = 0; > > - Â Â Â struct kvec *iov; > > - Â Â Â int len; > > - Â Â Â int n_iov = 0; > > - Â Â Â pgoff_t next; > > - Â Â Â int nr_pages; > > - Â Â Â __u64 offset = 0; > > + Â Â Â unsigned int pvec_pages; > > Â Â Â Âstruct cifsFileInfo *open_file; > > - Â Â Â struct cifs_tcon *tcon; > > - Â Â Â struct cifsInodeInfo *cifsi = CIFS_I(mapping->host); > > + Â Â Â struct cifs_writedata *wdata; > > Â Â Â Âstruct page *page; > > Â Â Â Âstruct pagevec pvec; > > + Â Â Â struct list_head pending; > > Â Â Â Â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 > > @@ -1121,27 +1158,19 @@ static int cifs_writepages(struct address_space *mapping, > > Â Â Â Âif (cifs_sb->wsize < PAGE_CACHE_SIZE) > > Â Â Â Â Â Â Â Âreturn generic_writepages(mapping, wbc); > > > > - Â Â Â iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL); > > - Â Â Â if (iov == NULL) > > - Â Â Â Â Â Â Â return generic_writepages(mapping, wbc); > > - > > Â Â Â Â/* > > Â Â Â Â * if there's no open file, then this is likely to fail too, > > Â Â Â Â * but it'll at least handle the return. Maybe it should be > > Â Â Â Â * a BUG() instead? > > Â Â Â Â */ > > Â Â Â Âopen_file = find_writable_file(CIFS_I(mapping->host), false); > > - Â Â Â if (!open_file) { > > - Â Â Â Â Â Â Â kfree(iov); > > + Â Â Â if (!open_file) > > Â Â Â Â Â Â Â Âreturn generic_writepages(mapping, wbc); > > - Â Â Â } > > - > > - Â Â Â tcon = tlink_tcon(open_file->tlink); > > Â Â Â ÂcifsFileInfo_put(open_file); > > > > - Â Â Â xid = GetXid(); > > - > > + Â Â Â INIT_LIST_HEAD(&pending); > > Â Â Â Âpagevec_init(&pvec, 0); > > + > > Â Â Â Âif (wbc->range_cyclic) { > > Â Â Â Â Â Â Â Âindex = mapping->writeback_index; /* Start from prev offset */ > > Â Â Â Â Â Â Â Âend = -1; > > @@ -1149,23 +1178,26 @@ static int cifs_writepages(struct address_space *mapping, > > Â Â Â Â Â Â Â Âindex = wbc->range_start >> PAGE_CACHE_SHIFT; > > Â Â Â Â Â Â Â Âend = wbc->range_end >> PAGE_CACHE_SHIFT; > > Â Â Â Â Â Â Â Âif (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) > > - Â Â Â Â Â Â Â Â Â Â Â range_whole = 1; > > - Â Â Â Â Â Â Â scanned = 1; > > + Â Â Â Â Â Â Â Â Â Â Â range_whole = true; > > + Â Â Â Â Â Â Â scanned = true; > > Â Â Â Â} > > Âretry: > > Â Â Â Âwhile (!done && (index <= end) && > > - Â Â Â Â Â Â Â(nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, > > + Â Â Â Â Â Â Â(pvec_pages = pagevec_lookup_tag(&pvec, mapping, &index, > > Â Â Â Â Â Â Â Â Â Â Â ÂPAGECACHE_TAG_DIRTY, > > Â Â Â Â Â Â Â Â Â Â Â Âmin(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) { > > - Â Â Â Â Â Â Â int first; > > Â Â Â Â Â Â Â Âunsigned int i; > > + Â Â Â Â Â Â Â unsigned int nr_pages = 0; > > + Â Â Â Â Â Â Â pgoff_t next = 0; > > > > - Â Â Â Â Â Â Â first = -1; > > - Â Â Â Â Â Â Â next = 0; > > - Â Â Â Â Â Â Â n_iov = 0; > > - Â Â Â Â Â Â Â bytes_to_write = 0; > > + Â Â Â Â Â Â Â wdata = cifs_writedata_alloc(); > > + Â Â Â Â Â Â Â if (!wdata) { > > + Â Â Â Â Â Â Â Â Â Â Â pagevec_release(&pvec); > > + Â Â Â Â Â Â Â Â Â Â Â rc = -ENOMEM; > > + Â Â Â Â Â Â Â Â Â Â Â break; > > + Â Â Â Â Â Â Â } > > > > - Â Â Â Â Â Â Â for (i = 0; i < nr_pages; i++) { > > + Â Â Â Â Â Â Â for (i = 0; i < pvec_pages; i++) { > > Â Â Â Â Â Â Â Â Â Â Â Âpage = pvec.pages[i]; > > Â Â Â Â Â Â Â Â Â Â Â Â/* > > Â Â Â Â Â Â Â Â Â Â Â Â * At this point we hold neither mapping->tree_lock nor > > @@ -1175,7 +1207,7 @@ retry: > > Â Â Â Â Â Â Â Â Â Â Â Â * mapping > > Â Â Â Â Â Â Â Â Â Â Â Â */ > > > > - Â Â Â Â Â Â Â Â Â Â Â if (first < 0) > > + Â Â Â Â Â Â Â Â Â Â Â if (nr_pages == 0) > > Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Âlock_page(page); > > Â Â Â Â Â Â Â Â Â Â Â Âelse if (!trylock_page(page)) > > Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Âbreak; > > @@ -1186,7 +1218,7 @@ retry: > > Â Â Â Â Â Â Â Â Â Â Â Â} > > > > Â Â Â Â Â Â Â Â Â Â Â Âif (!wbc->range_cyclic && page->index > end) { > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â done = 1; > > + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â done = true; > > Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Âunlock_page(page); > > Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Âbreak; > > Â Â Â Â Â Â Â Â Â Â Â Â} > > @@ -1213,119 +1245,103 @@ retry: > > Â Â Â Â Â Â Â Â Â Â Â Âset_page_writeback(page); > > > > Â Â Â Â Â Â Â Â Â Â Â Âif (page_offset(page) >= mapping->host->i_size) { > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â done = 1; > > + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â done = true; > > Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Âunlock_page(page); > > Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Âend_page_writeback(page); > > Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Âbreak; > > Â Â Â Â Â Â Â Â Â Â Â Â} > > > > - Â Â Â Â Â Â Â Â Â Â Â /* > > - Â Â Â Â Â Â Â Â Â Â Â Â* BB can we get rid of this? Âpages are held by pvec > > - Â Â Â Â Â Â Â Â Â Â Â Â*/ > > Â Â Â Â Â Â Â Â Â Â Â Âpage_cache_get(page); > > - > > - Â Â Â Â Â Â Â Â Â Â Â len = min(mapping->host->i_size - page_offset(page), > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â (loff_t)PAGE_CACHE_SIZE); > > - > > - Â Â Â Â Â Â Â Â Â Â Â /* reserve iov[0] for the smb header */ > > - Â Â Â Â Â Â Â Â Â Â Â n_iov++; > > - Â Â Â Â Â Â Â Â Â Â Â iov[n_iov].iov_base = kmap(page); > > - Â Â Â Â Â Â Â Â Â Â Â iov[n_iov].iov_len = len; > > - Â Â Â Â Â Â Â Â Â Â Â bytes_to_write += len; > > - > > - Â Â Â Â Â Â Â Â Â Â Â if (first < 0) { > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â first = i; > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â offset = page_offset(page); > > - Â Â Â Â Â Â Â Â Â Â Â } > > + Â Â Â Â Â Â Â Â Â Â Â wdata->pages[i] = page; > > Â Â Â Â Â Â Â Â Â Â Â Ânext = page->index + 1; > > - Â Â Â Â Â Â Â Â Â Â Â if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize) > > + Â Â Â Â Â Â Â Â Â Â Â ++nr_pages; > > + > > + Â Â Â Â Â Â Â Â Â Â Â /* stop here if we have enough for a full wsize write */ > > + Â Â Â Â Â Â Â Â Â Â Â if ((nr_pages + 1) * PAGE_CACHE_SIZE > cifs_sb->wsize) > > Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Âbreak; > > Â Â Â Â Â Â Â Â} > > - Â Â Â Â Â Â Â if (n_iov) { > > -retry_write: > > - Â Â Â Â Â Â Â Â Â Â Â open_file = find_writable_file(CIFS_I(mapping->host), > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â false); > > - Â Â Â Â Â Â Â Â Â Â Â if (!open_file) { > > + > > + Â Â Â Â Â Â Â if (wdata->pages[0] == NULL) { > > + Â Â Â Â Â Â Â Â Â Â Â /* Need to re-find the pages we skipped */ > > + Â Â Â Â Â Â Â Â Â Â Â index = pvec.pages[0]->index + 1; > > + Â Â Â Â Â Â Â Â Â Â Â pagevec_release(&pvec); > > + Â Â Â Â Â Â Â Â Â Â Â continue; > > + Â Â Â Â Â Â Â } > > + > > + Â Â Â Â Â Â Â pagevec_release(&pvec); > > + Â Â Â Â Â Â Â wdata->offset = page_offset(wdata->pages[0]); > > + > > + Â Â Â Â Â Â Â do { > > + Â Â Â Â Â Â Â Â Â Â Â if (wdata->cfile != NULL) > > + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â cifsFileInfo_put(wdata->cfile); > > + Â Â Â Â Â Â Â Â Â Â Â wdata->cfile = find_writable_file(CIFS_I(mapping->host), > > + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â false); > > + Â Â Â Â Â Â Â Â Â Â Â if (!wdata->cfile) { > > Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ÂcERROR(1, "No writable handles for inode"); > > Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Ârc = -EBADF; > > - Â Â Â Â Â Â Â Â Â Â Â } else { > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â rc = CIFSSMBWrite2(xid, tcon, open_file->netfid, > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Âbytes_to_write, offset, > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â&bytes_written, iov, n_iov, > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â0); > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â cifsFileInfo_put(open_file); > > + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break; > > Â Â Â Â Â Â Â Â Â Â Â Â} > > - > > - Â Â Â Â Â Â Â Â Â Â Â cFYI(1, "Write2 rc=%d, wrote=%u", rc, bytes_written); > > - > > - Â Â Â Â Â Â Â Â Â Â Â /* > > - Â Â Â Â Â Â Â Â Â Â Â Â* For now, treat a short write as if nothing got > > - Â Â Â Â Â Â Â Â Â Â Â Â* written. A zero length write however indicates > > - Â Â Â Â Â Â Â Â Â Â Â Â* ENOSPC or EFBIG. We have no way to know which > > - Â Â Â Â Â Â Â Â Â Â Â Â* though, so call it ENOSPC for now. EFBIG would > > - Â Â Â Â Â Â Â Â Â Â Â Â* get translated to AS_EIO anyway. > > - Â Â Â Â Â Â Â Â Â Â Â Â* > > - Â Â Â Â Â Â Â Â Â Â Â Â* FIXME: make it take into account the data that did > > - Â Â Â Â Â Â Â Â Â Â Â Â* Â Â Â Âget written > > - Â Â Â Â Â Â Â Â Â Â Â Â*/ > > - Â Â Â Â Â Â Â Â Â Â Â if (rc == 0) { > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (bytes_written == 0) > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â rc = -ENOSPC; > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â else if (bytes_written < bytes_to_write) > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â rc = -EAGAIN; > > + Â Â Â Â Â Â Â Â Â Â Â if (wbc->sync_mode == WB_SYNC_ALL) { > > + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â spin_lock(&mapping->private_lock); > > + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â list_move(&wdata->pending, &pending); > > + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â spin_unlock(&mapping->private_lock); > > Â Â Â Â Â Â Â Â Â Â Â Â} > > + Â Â Â Â Â Â Â Â Â Â Â rc = cifs_async_writev(wdata); > > + Â Â Â Â Â Â Â } while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN); > > > > - Â Â Â Â Â Â Â Â Â Â Â /* retry on data-integrity flush */ > > - Â Â Â Â Â Â Â Â Â Â Â if (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN) > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â goto retry_write; > > - > > - Â Â Â Â Â Â Â Â Â Â Â /* fix the stats and EOF */ > > - Â Â Â Â Â Â Â Â Â Â Â if (bytes_written > 0) { > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â cifs_stats_bytes_written(tcon, bytes_written); > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â cifs_update_eof(cifsi, offset, bytes_written); > > - Â Â Â Â Â Â Â Â Â Â Â } > > + Â Â Â Â Â Â Â for (i = 0; i < nr_pages; ++i) > > + Â Â Â Â Â Â Â Â Â Â Â unlock_page(wdata->pages[i]); > > > > - Â Â Â Â Â Â Â Â Â Â Â for (i = 0; i < n_iov; i++) { > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â page = pvec.pages[first + i]; > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â /* on retryable write error, redirty page */ > > + Â Â Â Â Â Â Â /* send failure -- clean up the mess */ > > + Â Â Â Â Â Â Â if (rc != 0) { > > + Â Â Â Â Â Â Â Â Â Â Â for (i = 0; i < nr_pages; ++i) { > > Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Âif (rc == -EAGAIN) > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â redirty_page_for_writepage(wbc, page); > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â else if (rc != 0) > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â SetPageError(page); > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â kunmap(page); > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â unlock_page(page); > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â end_page_writeback(page); > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â page_cache_release(page); > > + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â redirty_page_for_writepage(wbc, > > + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Âwdata->pages[i]); > > + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â else > > + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â SetPageError(wdata->pages[i]); > > + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â end_page_writeback(wdata->pages[i]); > > + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â page_cache_release(wdata->pages[i]); > > Â Â Â Â Â Â Â Â Â Â Â Â} > > - > > Â Â Â Â Â Â Â Â Â Â Â Âif (rc != -EAGAIN) > > Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Âmapping_set_error(mapping, rc); > > - Â Â Â Â Â Â Â Â Â Â Â else > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â rc = 0; > > - > > - Â Â Â Â Â Â Â Â Â Â Â if ((wbc->nr_to_write -= n_iov) <= 0) > > - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â done = 1; > > - Â Â Â Â Â Â Â Â Â Â Â index = next; > > - Â Â Â Â Â Â Â } else > > - Â Â Â Â Â Â Â Â Â Â Â /* Need to re-find the pages we skipped */ > > - Â Â Â Â Â Â Â Â Â Â Â index = pvec.pages[0]->index + 1; > > + Â Â Â Â Â Â Â Â Â Â Â kref_put(&wdata->refcount, cifs_writedata_release); > > + Â Â Â Â Â Â Â } else if (wbc->sync_mode == WB_SYNC_NONE) { > > + Â Â Â Â Â Â Â Â Â Â Â kref_put(&wdata->refcount, cifs_writedata_release); > > + Â Â Â Â Â Â Â } > > > > - Â Â Â Â Â Â Â pagevec_release(&pvec); > > + Â Â Â Â Â Â Â if ((wbc->nr_to_write -= nr_pages) <= 0) > > + Â Â Â Â Â Â Â Â Â Â Â done = true; > > + Â Â Â Â Â Â Â index = next; > > Â Â Â Â} > > + > > Â Â Â Â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; > > + Â Â Â Â Â Â Â scanned = true; > > Â Â Â Â Â Â Â Âindex = 0; > > Â Â Â Â Â Â Â Âgoto retry; > > Â Â Â Â} > > + > > + Â Â Â /* > > + Â Â Â Â* for WB_SYNC_ALL, we must wait until the writes complete. If any > > + Â Â Â Â* return -EAGAIN however, we need to retry the whole thing again. > > + Â Â Â Â* At that point nr_to_write will be all screwed up, but that > > + Â Â Â Â* shouldn't really matter for WB_SYNC_ALL (right?) > > + Â Â Â Â*/ > > + Â Â Â if (wbc->sync_mode == WB_SYNC_ALL) { > > + Â Â Â Â Â Â Â rc = cifs_wait_for_write_completion(mapping, &pending); > > + Â Â Â Â Â Â Â if (rc == -EAGAIN) { > > + Â Â Â Â Â Â Â Â Â Â Â index = wbc->range_start >> PAGE_CACHE_SHIFT; > > + Â Â Â Â Â Â Â Â Â Â Â goto retry; > > + Â Â Â Â Â Â Â } > > + Â Â Â } > > + > > Â Â Â Âif (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) > > Â Â Â Â Â Â Â Âmapping->writeback_index = index; > > > > - Â Â Â FreeXid(xid); > > - Â Â Â kfree(iov); > > Â Â Â Âreturn rc; > > Â} > > > > -- > > 1.7.4 > > > > -- > > To unsubscribe from this list: send the line "unsubscribe linux-cifs" in > > the body of a message to majordomo@xxxxxxxxxxxxxxx > > More majordomo info at Âhttp://vger.kernel.org/majordomo-info.html > > > > Good. I tested it and found out that it is ~20% faster when I write > ~gigabyte file on LAN against Windows 7 (MaxWorkItems is set to 4096, > otherwise - get STATUS_INSUFF_SERVER_RESOURCES after a write > finishes). > > As a test I do the following (python): > f = os.open('file', os.O_RDWR) > str = ''.join('q' for _ in xrange(4096)) > for _ in xrange(250000): > os.write(f, str) > os.close(f) > > Reviewed-and-Tested-by: Pavel Shilovsky <piastry@xxxxxxxxxxx> > Thanks for testing it! Yes, I think I'll need to make this patch respect the cifs_max_pending module parameter so we don't end up with too many outstanding writes at a time. At the same time, we probably ought to see about raising that above the hardcoded limit of 50, or come up with a better heuristic for autonegotiating it. I should have a new set in about a week or so, but I also need to do a bit of research on how best to negotiate a larger wsize. That should help performance even more I think. -- Jeff Layton <jlayton@xxxxxxxxxx> -- To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html