|
@@ -1878,6 +1878,86 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
+static unsigned int
|
|
|
+wdata_prepare_pages(struct cifs_writedata *wdata, unsigned int found_pages,
|
|
|
+ struct address_space *mapping,
|
|
|
+ struct writeback_control *wbc,
|
|
|
+ pgoff_t end, pgoff_t *index, pgoff_t *next, bool *done)
|
|
|
+{
|
|
|
+ unsigned int nr_pages = 0, i;
|
|
|
+ struct page *page;
|
|
|
+
|
|
|
+ for (i = 0; i < found_pages; i++) {
|
|
|
+ page = wdata->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 (nr_pages == 0)
|
|
|
+ lock_page(page);
|
|
|
+ else if (!trylock_page(page))
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (unlikely(page->mapping != mapping)) {
|
|
|
+ unlock_page(page);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!wbc->range_cyclic && page->index > end) {
|
|
|
+ *done = true;
|
|
|
+ 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) ||
|
|
|
+ !clear_page_dirty_for_io(page)) {
|
|
|
+ unlock_page(page);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * This actually clears the dirty bit in the radix tree.
|
|
|
+ * See cifs_writepage() for more commentary.
|
|
|
+ */
|
|
|
+ set_page_writeback(page);
|
|
|
+ if (page_offset(page) >= i_size_read(mapping->host)) {
|
|
|
+ *done = true;
|
|
|
+ unlock_page(page);
|
|
|
+ end_page_writeback(page);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ wdata->pages[i] = page;
|
|
|
+ *next = page->index + 1;
|
|
|
+ ++nr_pages;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* reset index to refind any pages skipped */
|
|
|
+ if (nr_pages == 0)
|
|
|
+ *index = wdata->pages[0]->index + 1;
|
|
|
+
|
|
|
+ /* put any pages we aren't going to use */
|
|
|
+ for (i = nr_pages; i < found_pages; i++) {
|
|
|
+ page_cache_release(wdata->pages[i]);
|
|
|
+ wdata->pages[i] = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return nr_pages;
|
|
|
+}
|
|
|
+
|
|
|
static int cifs_writepages(struct address_space *mapping,
|
|
|
struct writeback_control *wbc)
|
|
|
{
|
|
@@ -1886,7 +1966,6 @@ static int cifs_writepages(struct address_space *mapping,
|
|
|
pgoff_t end, index;
|
|
|
struct cifs_writedata *wdata;
|
|
|
struct TCP_Server_Info *server;
|
|
|
- struct page *page;
|
|
|
int rc = 0;
|
|
|
|
|
|
/*
|
|
@@ -1944,75 +2023,8 @@ retry:
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- nr_pages = 0;
|
|
|
- for (i = 0; i < found_pages; i++) {
|
|
|
- page = wdata->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 (nr_pages == 0)
|
|
|
- lock_page(page);
|
|
|
- else if (!trylock_page(page))
|
|
|
- break;
|
|
|
-
|
|
|
- if (unlikely(page->mapping != mapping)) {
|
|
|
- unlock_page(page);
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (!wbc->range_cyclic && page->index > end) {
|
|
|
- done = true;
|
|
|
- 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) ||
|
|
|
- !clear_page_dirty_for_io(page)) {
|
|
|
- unlock_page(page);
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * This actually clears the dirty bit in the radix tree.
|
|
|
- * See cifs_writepage() for more commentary.
|
|
|
- */
|
|
|
- set_page_writeback(page);
|
|
|
-
|
|
|
- if (page_offset(page) >= i_size_read(mapping->host)) {
|
|
|
- done = true;
|
|
|
- unlock_page(page);
|
|
|
- end_page_writeback(page);
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- wdata->pages[i] = page;
|
|
|
- next = page->index + 1;
|
|
|
- ++nr_pages;
|
|
|
- }
|
|
|
-
|
|
|
- /* reset index to refind any pages skipped */
|
|
|
- if (nr_pages == 0)
|
|
|
- index = wdata->pages[0]->index + 1;
|
|
|
-
|
|
|
- /* put any pages we aren't going to use */
|
|
|
- for (i = nr_pages; i < found_pages; i++) {
|
|
|
- page_cache_release(wdata->pages[i]);
|
|
|
- wdata->pages[i] = NULL;
|
|
|
- }
|
|
|
+ nr_pages = wdata_prepare_pages(wdata, found_pages, mapping, wbc,
|
|
|
+ end, &index, &next, &done);
|
|
|
|
|
|
/* nothing to write? */
|
|
|
if (nr_pages == 0) {
|