/** * 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_doio(desc); } }
/** * nfs_pageio_complete - Complete I/O on an nfs_pageio_descriptor * @desc: pointer to io descriptor */ void nfs_pageio_complete(struct nfs_pageio_descriptor *desc) { for (;;) { nfs_pageio_doio(desc); if (!desc->pg_recoalesce) break; if (!nfs_do_recoalesce(desc)) break; } }
/** * nfs_pageio_add_request - Attempt to coalesce a request into a page list. * @desc: destination io descriptor * @req: request * * Returns true if the request 'req' was successfully coalesced into the * existing list of pages 'desc'. */ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, struct nfs_page *req) { while (!nfs_pageio_do_add_request(desc, req)) { nfs_pageio_doio(desc); if (desc->pg_error < 0) return 0; } return 1; }
/** * nfs_pageio_add_request - Attempt to coalesce a request into a page list. * @desc: destination io descriptor * @req: request * * Returns true if the request 'req' was successfully coalesced into the * existing list of pages 'desc'. */ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, struct nfs_page *req) { while (!nfs_pageio_do_add_request(desc, req)) { desc->pg_moreio = 1; nfs_pageio_doio(desc); if (desc->pg_error < 0) return 0; desc->pg_moreio = 0; if (desc->pg_recoalesce) return 0; } return 1; }
/** * nfs_pageio_complete - Complete I/O on an nfs_pageio_descriptor * @desc: pointer to io descriptor */ void nfs_pageio_complete(struct nfs_pageio_descriptor *desc) { nfs_pageio_doio(desc); }
/** * nfs_pageio_add_request - Attempt to coalesce a request into a page list. * @desc: destination io descriptor * @req: request * * This may split a request into subrequests which are all part of the * same page group. * * Returns true if the request 'req' was successfully coalesced into the * existing list of pages 'desc'. */ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, struct nfs_page *req) { struct nfs_page *subreq; unsigned int bytes_left = 0; unsigned int offset, pgbase; nfs_page_group_lock(req, false); subreq = req; bytes_left = subreq->wb_bytes; offset = subreq->wb_offset; pgbase = subreq->wb_pgbase; do { if (!nfs_pageio_do_add_request(desc, subreq)) { /* make sure pg_test call(s) did nothing */ WARN_ON_ONCE(subreq->wb_bytes != bytes_left); WARN_ON_ONCE(subreq->wb_offset != offset); WARN_ON_ONCE(subreq->wb_pgbase != pgbase); nfs_page_group_unlock(req); desc->pg_moreio = 1; nfs_pageio_doio(desc); if (desc->pg_error < 0) return 0; if (desc->pg_recoalesce) return 0; /* retry add_request for this subreq */ nfs_page_group_lock(req, false); continue; } /* check for buggy pg_test call(s) */ WARN_ON_ONCE(subreq->wb_bytes + subreq->wb_pgbase > PAGE_SIZE); WARN_ON_ONCE(subreq->wb_bytes > bytes_left); WARN_ON_ONCE(subreq->wb_bytes == 0); bytes_left -= subreq->wb_bytes; offset += subreq->wb_bytes; pgbase += subreq->wb_bytes; if (bytes_left) { subreq = nfs_create_request(req->wb_context, req->wb_page, subreq, pgbase, bytes_left); if (IS_ERR(subreq)) goto err_ptr; nfs_lock_request(subreq); subreq->wb_offset = offset; subreq->wb_index = req->wb_index; } } while (bytes_left > 0); nfs_page_group_unlock(req); return 1; err_ptr: desc->pg_error = PTR_ERR(subreq); nfs_page_group_unlock(req); return 0; }