/* * Try to update an existing write request, or create one if there is none. * * Note: Should always be called with the Page Lock held to prevent races * if we have to add a new request. Also assumes that the caller has * already called nfs_flush_incompatible() if necessary. */ static struct nfs_page * nfs_setup_write_request(struct nfs_open_context* ctx, struct page *page, unsigned int offset, unsigned int bytes) { struct inode *inode = page->mapping->host; struct nfs_page *req; int error; req = nfs_try_to_update_request(inode, page, offset, bytes); if (req != NULL) goto out; req = nfs_create_request(ctx, inode, page, offset, bytes); if (IS_ERR(req)) goto out; error = nfs_inode_add_request(inode, req); if (error != 0) { nfs_release_request(req); req = ERR_PTR(error); } out: return req; }
/** * 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; }