Re: [PATCH 5/5] cifs: convert cifs_writepages to use async writes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux