int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) { struct inode *inode = mapping->host; unsigned long *bitlock = &NFS_I(inode)->flags; struct nfs_pageio_descriptor pgio; int err; /* Stop dirtying of new pages while we sync */ err = wait_on_bit_lock(bitlock, NFS_INO_FLUSHING, nfs_wait_bit_killable, TASK_KILLABLE); if (err) goto out_err; nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES); nfs_pageio_init_write(&pgio, inode, wb_priority(wbc)); err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio); nfs_pageio_complete(&pgio); clear_bit_unlock(NFS_INO_FLUSHING, bitlock); smp_mb__after_clear_bit(); wake_up_bit(bitlock, NFS_INO_FLUSHING); if (err < 0) goto out_err; err = pgio.pg_error; if (err < 0) goto out_err; return 0; out_err: return err; }
/** * nfs_pageio_cond_complete - Conditional I/O completion * @desc: pointer to io descriptor * @index: page index * * It is important to ensure that processes don't try to take locks * on non-contiguous ranges of pages as that might deadlock. This * function should be called before attempting to wait on a locked * nfs_page. It will complete the I/O if the page index 'index' * is not contiguous with the existing list of pages in 'desc'. */ void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index) { if (!list_empty(&desc->pg_list)) { struct nfs_page *prev = nfs_list_entry(desc->pg_list.prev); if (index != prev->wb_index + 1) nfs_pageio_complete(desc); } }
/* * Write an mmapped page to the server. */ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc) { struct nfs_pageio_descriptor pgio; int err; nfs_pageio_init_write(&pgio, page->mapping->host, wb_priority(wbc)); err = nfs_do_writepage(page, wbc, &pgio); nfs_pageio_complete(&pgio); if (err < 0) return err; if (pgio.pg_error < 0) return pgio.pg_error; return 0; }
/* * nfs_pageio_resend - Transfer requests to new descriptor and resend * @hdr - the pgio header to move request from * @desc - the pageio descriptor to add requests to * * Try to move each request (nfs_page) from @hdr to @desc then attempt * to send them. * * Returns 0 on success and < 0 on error. */ int nfs_pageio_resend(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr) { LIST_HEAD(failed); desc->pg_dreq = hdr->dreq; while (!list_empty(&hdr->pages)) { struct nfs_page *req = nfs_list_entry(hdr->pages.next); nfs_list_remove_request(req); if (!nfs_pageio_add_request(desc, req)) nfs_list_add_request(req, &failed); } nfs_pageio_complete(desc); if (!list_empty(&failed)) { list_move(&failed, &hdr->pages); return -EIO; } return 0; }