|
@@ -1896,28 +1896,80 @@ cifs_writedata_release(struct kref *refcount)
|
|
static void
|
|
static void
|
|
cifs_writev_requeue(struct cifs_writedata *wdata)
|
|
cifs_writev_requeue(struct cifs_writedata *wdata)
|
|
{
|
|
{
|
|
- int i, rc;
|
|
|
|
|
|
+ int i, rc = 0;
|
|
struct inode *inode = wdata->cfile->dentry->d_inode;
|
|
struct inode *inode = wdata->cfile->dentry->d_inode;
|
|
struct TCP_Server_Info *server;
|
|
struct TCP_Server_Info *server;
|
|
|
|
+ unsigned int rest_len;
|
|
|
|
|
|
- for (i = 0; i < wdata->nr_pages; i++) {
|
|
|
|
- lock_page(wdata->pages[i]);
|
|
|
|
- clear_page_dirty_for_io(wdata->pages[i]);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ server = tlink_tcon(wdata->cfile->tlink)->ses->server;
|
|
|
|
+ i = 0;
|
|
|
|
+ rest_len = wdata->bytes;
|
|
do {
|
|
do {
|
|
- server = tlink_tcon(wdata->cfile->tlink)->ses->server;
|
|
|
|
- rc = server->ops->async_writev(wdata, cifs_writedata_release);
|
|
|
|
- } while (rc == -EAGAIN);
|
|
|
|
|
|
+ struct cifs_writedata *wdata2;
|
|
|
|
+ unsigned int j, nr_pages, wsize, tailsz, cur_len;
|
|
|
|
+
|
|
|
|
+ wsize = server->ops->wp_retry_size(inode);
|
|
|
|
+ if (wsize < rest_len) {
|
|
|
|
+ nr_pages = wsize / PAGE_CACHE_SIZE;
|
|
|
|
+ if (!nr_pages) {
|
|
|
|
+ rc = -ENOTSUPP;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ cur_len = nr_pages * PAGE_CACHE_SIZE;
|
|
|
|
+ tailsz = PAGE_CACHE_SIZE;
|
|
|
|
+ } else {
|
|
|
|
+ nr_pages = DIV_ROUND_UP(rest_len, PAGE_CACHE_SIZE);
|
|
|
|
+ cur_len = rest_len;
|
|
|
|
+ tailsz = rest_len - (nr_pages - 1) * PAGE_CACHE_SIZE;
|
|
|
|
+ }
|
|
|
|
|
|
- for (i = 0; i < wdata->nr_pages; i++) {
|
|
|
|
- unlock_page(wdata->pages[i]);
|
|
|
|
- if (rc != 0) {
|
|
|
|
- SetPageError(wdata->pages[i]);
|
|
|
|
- end_page_writeback(wdata->pages[i]);
|
|
|
|
- page_cache_release(wdata->pages[i]);
|
|
|
|
|
|
+ wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
|
|
|
|
+ if (!wdata2) {
|
|
|
|
+ rc = -ENOMEM;
|
|
|
|
+ break;
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
+
|
|
|
|
+ for (j = 0; j < nr_pages; j++) {
|
|
|
|
+ wdata2->pages[j] = wdata->pages[i + j];
|
|
|
|
+ lock_page(wdata2->pages[j]);
|
|
|
|
+ clear_page_dirty_for_io(wdata2->pages[j]);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ wdata2->sync_mode = wdata->sync_mode;
|
|
|
|
+ wdata2->nr_pages = nr_pages;
|
|
|
|
+ wdata2->offset = page_offset(wdata2->pages[0]);
|
|
|
|
+ wdata2->pagesz = PAGE_CACHE_SIZE;
|
|
|
|
+ wdata2->tailsz = tailsz;
|
|
|
|
+ wdata2->bytes = cur_len;
|
|
|
|
+
|
|
|
|
+ wdata2->cfile = find_writable_file(CIFS_I(inode), false);
|
|
|
|
+ if (!wdata2->cfile) {
|
|
|
|
+ cifs_dbg(VFS, "No writable handles for inode\n");
|
|
|
|
+ rc = -EBADF;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ wdata2->pid = wdata2->cfile->pid;
|
|
|
|
+ rc = server->ops->async_writev(wdata2, cifs_writedata_release);
|
|
|
|
+
|
|
|
|
+ for (j = 0; j < nr_pages; j++) {
|
|
|
|
+ unlock_page(wdata2->pages[j]);
|
|
|
|
+ if (rc != 0 && rc != -EAGAIN) {
|
|
|
|
+ SetPageError(wdata2->pages[j]);
|
|
|
|
+ end_page_writeback(wdata2->pages[j]);
|
|
|
|
+ page_cache_release(wdata2->pages[j]);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (rc) {
|
|
|
|
+ kref_put(&wdata2->refcount, cifs_writedata_release);
|
|
|
|
+ if (rc == -EAGAIN)
|
|
|
|
+ continue;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rest_len -= cur_len;
|
|
|
|
+ i += nr_pages;
|
|
|
|
+ } while (i < wdata->nr_pages);
|
|
|
|
|
|
mapping_set_error(inode->i_mapping, rc);
|
|
mapping_set_error(inode->i_mapping, rc);
|
|
kref_put(&wdata->refcount, cifs_writedata_release);
|
|
kref_put(&wdata->refcount, cifs_writedata_release);
|