···12851286static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)1287{1288- struct nfs_inode *nfsi = NFS_I(inode);1289 unsigned long ret = 0;12901291 if ((fattr->valid & NFS_ATTR_FATTR_PRECHANGE)···1314 if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE)1315 && (fattr->valid & NFS_ATTR_FATTR_SIZE)1316 && i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size)1317- && nfsi->nrequests == 0) {1318 i_size_write(inode, nfs_size_to_loff_t(fattr->size));1319 ret |= NFS_INO_INVALID_ATTR;1320 }···1822 if (new_isize != cur_isize) {1823 /* Do we perhaps have any outstanding writes, or has1824 * the file grown beyond our last write? */1825- if (nfsi->nrequests == 0 || new_isize > cur_isize) {1826 i_size_write(inode, new_isize);1827 if (!have_writers)1828 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;···2011 INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);2012 INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);2013 INIT_LIST_HEAD(&nfsi->commit_info.list);2014- nfsi->nrequests = 0;2015- nfsi->commit_info.ncommit = 0;2016 atomic_set(&nfsi->commit_info.rpcs_out, 0);2017 init_rwsem(&nfsi->rmdir_sem);02018 nfs4_init_once(nfsi);2019}2020
···12851286static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)1287{01288 unsigned long ret = 0;12891290 if ((fattr->valid & NFS_ATTR_FATTR_PRECHANGE)···1315 if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE)1316 && (fattr->valid & NFS_ATTR_FATTR_SIZE)1317 && i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size)1318+ && !nfs_have_writebacks(inode)) {1319 i_size_write(inode, nfs_size_to_loff_t(fattr->size));1320 ret |= NFS_INO_INVALID_ATTR;1321 }···1823 if (new_isize != cur_isize) {1824 /* Do we perhaps have any outstanding writes, or has1825 * the file grown beyond our last write? */1826+ if (!nfs_have_writebacks(inode) || new_isize > cur_isize) {1827 i_size_write(inode, new_isize);1828 if (!have_writers)1829 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;···2012 INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);2013 INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);2014 INIT_LIST_HEAD(&nfsi->commit_info.list);2015+ atomic_long_set(&nfsi->nrequests, 0);2016+ atomic_long_set(&nfsi->commit_info.ncommit, 0);2017 atomic_set(&nfsi->commit_info.rpcs_out, 0);2018 init_rwsem(&nfsi->rmdir_sem);2019+ mutex_init(&nfsi->commit_mutex);2020 nfs4_init_once(nfsi);2021}2022
+19-48
fs/nfs/pagelist.c
···134/*135 * nfs_page_group_lock - lock the head of the page group136 * @req - request in group that is to be locked137- * @nonblock - if true don't block waiting for lock138 *139- * this lock must be held if modifying the page group list0140 *141- * return 0 on success, < 0 on error: -EDELAY if nonblocking or the142- * result from wait_on_bit_lock143- *144- * NOTE: calling with nonblock=false should always have set the145- * lock bit (see fs/buffer.c and other uses of wait_on_bit_lock146- * with TASK_UNINTERRUPTIBLE), so there is no need to check the result.147 */148int149-nfs_page_group_lock(struct nfs_page *req, bool nonblock)150{151 struct nfs_page *head = req->wb_head;152···150 if (!test_and_set_bit(PG_HEADLOCK, &head->wb_flags))151 return 0;152153- if (!nonblock) {154- set_bit(PG_CONTENDED1, &head->wb_flags);155- smp_mb__after_atomic();156- return wait_on_bit_lock(&head->wb_flags, PG_HEADLOCK,157- TASK_UNINTERRUPTIBLE);158- }159-160- return -EAGAIN;161-}162-163-/*164- * nfs_page_group_lock_wait - wait for the lock to clear, but don't grab it165- * @req - a request in the group166- *167- * This is a blocking call to wait for the group lock to be cleared.168- */169-void170-nfs_page_group_lock_wait(struct nfs_page *req)171-{172- struct nfs_page *head = req->wb_head;173-174- WARN_ON_ONCE(head != head->wb_head);175-176- if (!test_bit(PG_HEADLOCK, &head->wb_flags))177- return;178 set_bit(PG_CONTENDED1, &head->wb_flags);179 smp_mb__after_atomic();180- wait_on_bit(&head->wb_flags, PG_HEADLOCK,181- TASK_UNINTERRUPTIBLE);182}183184/*···216{217 bool ret;218219- nfs_page_group_lock(req, false);220 ret = nfs_page_group_sync_on_bit_locked(req, bit);221 nfs_page_group_unlock(req);222···258 inode = page_file_mapping(req->wb_page)->host;259 set_bit(PG_INODE_REF, &req->wb_flags);260 kref_get(&req->wb_kref);261- spin_lock(&inode->i_lock);262- NFS_I(inode)->nrequests++;263- spin_unlock(&inode->i_lock);264 }265 }266}···274nfs_page_group_destroy(struct kref *kref)275{276 struct nfs_page *req = container_of(kref, struct nfs_page, wb_kref);0277 struct nfs_page *tmp, *next;278279- /* subrequests must release the ref on the head request */280- if (req->wb_head != req)281- nfs_release_request(req->wb_head);282-283 if (!nfs_page_group_sync_on_bit(req, PG_TEARDOWN))284- return;285286 tmp = req;287 do {···289 nfs_free_request(tmp);290 tmp = next;291 } while (tmp != req);0000292}293294/**···434{435 kref_put(&req->wb_kref, nfs_page_group_destroy);436}0437438/**439 * nfs_wait_on_request - Wait for a request to complete.···453 return wait_on_bit_io(&req->wb_flags, PG_BUSY,454 TASK_UNINTERRUPTIBLE);455}0456457/*458 * nfs_generic_pg_test - determine if requests can be coalesced···1007 unsigned int bytes_left = 0;1008 unsigned int offset, pgbase;10091010- nfs_page_group_lock(req, false);10111012 subreq = req;1013 bytes_left = subreq->wb_bytes;···1029 if (mirror->pg_recoalesce)1030 return 0;1031 /* retry add_request for this subreq */1032- nfs_page_group_lock(req, false);1033 continue;1034 }1035···11261127 for (midx = 0; midx < desc->pg_mirror_count; midx++) {1128 if (midx) {1129- nfs_page_group_lock(req, false);11301131 /* find the last request */1132 for (lastreq = req->wb_head;
···134/*135 * nfs_page_group_lock - lock the head of the page group136 * @req - request in group that is to be locked0137 *138+ * this lock must be held when traversing or modifying the page139+ * group list140 *141+ * return 0 on success, < 0 on error00000142 */143int144+nfs_page_group_lock(struct nfs_page *req)145{146 struct nfs_page *head = req->wb_head;147···155 if (!test_and_set_bit(PG_HEADLOCK, &head->wb_flags))156 return 0;1570000000000000000000000000158 set_bit(PG_CONTENDED1, &head->wb_flags);159 smp_mb__after_atomic();160+ return wait_on_bit_lock(&head->wb_flags, PG_HEADLOCK,161+ TASK_UNINTERRUPTIBLE);162}163164/*···246{247 bool ret;248249+ nfs_page_group_lock(req);250 ret = nfs_page_group_sync_on_bit_locked(req, bit);251 nfs_page_group_unlock(req);252···288 inode = page_file_mapping(req->wb_page)->host;289 set_bit(PG_INODE_REF, &req->wb_flags);290 kref_get(&req->wb_kref);291+ atomic_long_inc(&NFS_I(inode)->nrequests);00292 }293 }294}···306nfs_page_group_destroy(struct kref *kref)307{308 struct nfs_page *req = container_of(kref, struct nfs_page, wb_kref);309+ struct nfs_page *head = req->wb_head;310 struct nfs_page *tmp, *next;3110000312 if (!nfs_page_group_sync_on_bit(req, PG_TEARDOWN))313+ goto out;314315 tmp = req;316 do {···324 nfs_free_request(tmp);325 tmp = next;326 } while (tmp != req);327+out:328+ /* subrequests must release the ref on the head request */329+ if (head != req)330+ nfs_release_request(head);331}332333/**···465{466 kref_put(&req->wb_kref, nfs_page_group_destroy);467}468+EXPORT_SYMBOL_GPL(nfs_release_request);469470/**471 * nfs_wait_on_request - Wait for a request to complete.···483 return wait_on_bit_io(&req->wb_flags, PG_BUSY,484 TASK_UNINTERRUPTIBLE);485}486+EXPORT_SYMBOL_GPL(nfs_wait_on_request);487488/*489 * nfs_generic_pg_test - determine if requests can be coalesced···1036 unsigned int bytes_left = 0;1037 unsigned int offset, pgbase;10381039+ nfs_page_group_lock(req);10401041 subreq = req;1042 bytes_left = subreq->wb_bytes;···1058 if (mirror->pg_recoalesce)1059 return 0;1060 /* retry add_request for this subreq */1061+ nfs_page_group_lock(req);1062 continue;1063 }1064···11551156 for (midx = 0; midx < desc->pg_mirror_count; midx++) {1157 if (midx) {1158+ nfs_page_group_lock(req);11591160 /* find the last request */1161 for (lastreq = req->wb_head;
···83 }84out:85 nfs_request_remove_commit_list(req, cinfo);86- pnfs_put_lseg_locked(freeme);87}88EXPORT_SYMBOL_GPL(pnfs_generic_clear_request_commit);89···91pnfs_generic_transfer_commit_list(struct list_head *src, struct list_head *dst,92 struct nfs_commit_info *cinfo, int max)93{94- struct nfs_page *req, *tmp;95 int ret = 0;9697- list_for_each_entry_safe(req, tmp, src, wb_list) {98- if (!nfs_lock_request(req))99- continue;100 kref_get(&req->wb_kref);101- if (cond_resched_lock(&cinfo->inode->i_lock))102- list_safe_reset_next(req, tmp, wb_list);00000000103 nfs_request_remove_commit_list(req, cinfo);104 clear_bit(PG_COMMIT_TO_DS, &req->wb_flags);105 nfs_list_add_request(req, dst);106 ret++;107 if ((ret == max) && !cinfo->dreq)108 break;0109 }110 return ret;111}···128 struct list_head *dst = &bucket->committing;129 int ret;130131- lockdep_assert_held(&cinfo->inode->i_lock);132 ret = pnfs_generic_transfer_commit_list(src, dst, cinfo, max);133 if (ret) {134 cinfo->ds->nwritten -= ret;···136 if (bucket->clseg == NULL)137 bucket->clseg = pnfs_get_lseg(bucket->wlseg);138 if (list_empty(src)) {139- pnfs_put_lseg_locked(bucket->wlseg);140 bucket->wlseg = NULL;141 }142 }···151{152 int i, rv = 0, cnt;153154- lockdep_assert_held(&cinfo->inode->i_lock);155 for (i = 0; i < cinfo->ds->nbuckets && max != 0; i++) {156 cnt = pnfs_generic_scan_ds_commit_list(&cinfo->ds->buckets[i],157 cinfo, max);···171 int nwritten;172 int i;173174- lockdep_assert_held(&cinfo->inode->i_lock);175restart:176 for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) {177 nwritten = pnfs_generic_transfer_commit_list(&b->written,···962 struct list_head *list;963 struct pnfs_commit_bucket *buckets;964965- spin_lock(&cinfo->inode->i_lock);966 buckets = cinfo->ds->buckets;967 list = &buckets[ds_commit_idx].written;968 if (list_empty(list)) {969 if (!pnfs_is_valid_lseg(lseg)) {970- spin_unlock(&cinfo->inode->i_lock);971 cinfo->completion_ops->resched_write(cinfo, req);972 return;973 }···984 cinfo->ds->nwritten++;985986 nfs_request_add_commit_list_locked(req, list, cinfo);987- spin_unlock(&cinfo->inode->i_lock);988 nfs_mark_page_unstable(req->wb_page, cinfo);989}990EXPORT_SYMBOL_GPL(pnfs_layout_mark_request_commit);
···83 }84out:85 nfs_request_remove_commit_list(req, cinfo);86+ pnfs_put_lseg(freeme);87}88EXPORT_SYMBOL_GPL(pnfs_generic_clear_request_commit);89···91pnfs_generic_transfer_commit_list(struct list_head *src, struct list_head *dst,92 struct nfs_commit_info *cinfo, int max)93{94+ struct nfs_page *req;95 int ret = 0;9697+ while(!list_empty(src)) {98+ req = list_first_entry(src, struct nfs_page, wb_list);99+100 kref_get(&req->wb_kref);101+ if (!nfs_lock_request(req)) {102+ int status;103+ mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);104+ status = nfs_wait_on_request(req);105+ nfs_release_request(req);106+ mutex_lock(&NFS_I(cinfo->inode)->commit_mutex);107+ if (status < 0)108+ break;109+ continue;110+ }111 nfs_request_remove_commit_list(req, cinfo);112 clear_bit(PG_COMMIT_TO_DS, &req->wb_flags);113 nfs_list_add_request(req, dst);114 ret++;115 if ((ret == max) && !cinfo->dreq)116 break;117+ cond_resched();118 }119 return ret;120}···119 struct list_head *dst = &bucket->committing;120 int ret;121122+ lockdep_assert_held(&NFS_I(cinfo->inode)->commit_mutex);123 ret = pnfs_generic_transfer_commit_list(src, dst, cinfo, max);124 if (ret) {125 cinfo->ds->nwritten -= ret;···127 if (bucket->clseg == NULL)128 bucket->clseg = pnfs_get_lseg(bucket->wlseg);129 if (list_empty(src)) {130+ pnfs_put_lseg(bucket->wlseg);131 bucket->wlseg = NULL;132 }133 }···142{143 int i, rv = 0, cnt;144145+ lockdep_assert_held(&NFS_I(cinfo->inode)->commit_mutex);146 for (i = 0; i < cinfo->ds->nbuckets && max != 0; i++) {147 cnt = pnfs_generic_scan_ds_commit_list(&cinfo->ds->buckets[i],148 cinfo, max);···162 int nwritten;163 int i;164165+ lockdep_assert_held(&NFS_I(cinfo->inode)->commit_mutex);166restart:167 for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) {168 nwritten = pnfs_generic_transfer_commit_list(&b->written,···953 struct list_head *list;954 struct pnfs_commit_bucket *buckets;955956+ mutex_lock(&NFS_I(cinfo->inode)->commit_mutex);957 buckets = cinfo->ds->buckets;958 list = &buckets[ds_commit_idx].written;959 if (list_empty(list)) {960 if (!pnfs_is_valid_lseg(lseg)) {961+ mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);962 cinfo->completion_ops->resched_write(cinfo, req);963 return;964 }···975 cinfo->ds->nwritten++;976977 nfs_request_add_commit_list_locked(req, list, cinfo);978+ mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);979 nfs_mark_page_unstable(req->wb_page, cinfo);980}981EXPORT_SYMBOL_GPL(pnfs_layout_mark_request_commit);
+208-236
fs/nfs/write.c
···154 set_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);155}15600000000157/*158 * nfs_page_find_head_request_locked - find head request associated with @page159 *···170 * returns matching head request with reference held, or NULL if not found.171 */172static struct nfs_page *173-nfs_page_find_head_request_locked(struct nfs_inode *nfsi, struct page *page)174{175- struct nfs_page *req = NULL;0176177- if (PagePrivate(page))178- req = (struct nfs_page *)page_private(page);179- else if (unlikely(PageSwapCache(page)))180- req = nfs_page_search_commits_for_head_request_locked(nfsi,181- page);182-183 if (req) {184 WARN_ON_ONCE(req->wb_head != req);185 kref_get(&req->wb_kref);186 }000187000000000000000000188 return req;189}190···215 */216static struct nfs_page *nfs_page_find_head_request(struct page *page)217{218- struct inode *inode = page_file_mapping(page)->host;219- struct nfs_page *req = NULL;220221- spin_lock(&inode->i_lock);222- req = nfs_page_find_head_request_locked(NFS_I(inode), page);223- spin_unlock(&inode->i_lock);224 return req;225}226···268{269 struct nfs_page *req;270271- WARN_ON_ONCE(head != head->wb_head);272- WARN_ON_ONCE(!test_bit(PG_HEADLOCK, &head->wb_head->wb_flags));273-274 req = head;275 do {276 if (page_offset >= req->wb_pgbase &&···293 unsigned int pos = 0;294 unsigned int len = nfs_page_length(req->wb_page);295296- nfs_page_group_lock(req, false);297298- do {299 tmp = nfs_page_group_search_locked(req->wb_head, pos);300- if (tmp) {301- /* no way this should happen */302- WARN_ON_ONCE(tmp->wb_pgbase != pos);303- pos += tmp->wb_bytes - (pos - tmp->wb_pgbase);304- }305- } while (tmp && pos < len);306307 nfs_page_group_unlock(req);308- WARN_ON_ONCE(pos > len);309- return pos == len;310}311312/* We can set the PG_uptodate flag if we see that a write request···354{355 struct inode *inode = page_file_mapping(req->wb_page)->host;356 struct nfs_server *nfss = NFS_SERVER(inode);0357358- if (!nfs_page_group_sync_on_bit(req, PG_WB_END))00359 return;360361 end_page_writeback(req->wb_page);362 if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH)363 clear_bdi_congested(inode_to_bdi(inode), BLK_RW_ASYNC);364}365-366-367-/* nfs_page_group_clear_bits368- * @req - an nfs request369- * clears all page group related bits from @req370- */371-static void372-nfs_page_group_clear_bits(struct nfs_page *req)373-{374- clear_bit(PG_TEARDOWN, &req->wb_flags);375- clear_bit(PG_UNLOCKPAGE, &req->wb_flags);376- clear_bit(PG_UPTODATE, &req->wb_flags);377- clear_bit(PG_WB_END, &req->wb_flags);378- clear_bit(PG_REMOVE, &req->wb_flags);379-}380-381382/*383 * nfs_unroll_locks_and_wait - unlock all newly locked reqs and wait on @req···374 * @inode - inode associated with request page group, must be holding inode lock375 * @head - head request of page group, must be holding head lock376 * @req - request that couldn't lock and needs to wait on the req bit lock377- * @nonblock - if true, don't actually wait378 *379- * NOTE: this must be called holding page_group bit lock and inode spin lock380- * and BOTH will be released before returning.381 *382 * returns 0 on success, < 0 on error.383 */384-static int385-nfs_unroll_locks_and_wait(struct inode *inode, struct nfs_page *head,386- struct nfs_page *req, bool nonblock)387- __releases(&inode->i_lock)388{389 struct nfs_page *tmp;390- int ret;391392 /* relinquish all the locks successfully grabbed this run */393- for (tmp = head ; tmp != req; tmp = tmp->wb_this_page)394- nfs_unlock_request(tmp);395-396- WARN_ON_ONCE(test_bit(PG_TEARDOWN, &req->wb_flags));397-398- /* grab a ref on the request that will be waited on */399- kref_get(&req->wb_kref);400-401- nfs_page_group_unlock(head);402- spin_unlock(&inode->i_lock);403-404- /* release ref from nfs_page_find_head_request_locked */405- nfs_release_request(head);406-407- if (!nonblock)408- ret = nfs_wait_on_request(req);409- else410- ret = -EAGAIN;411- nfs_release_request(req);412-413- return ret;414}415416/*···406 */407static void408nfs_destroy_unlinked_subrequests(struct nfs_page *destroy_list,409- struct nfs_page *old_head)0410{411 while (destroy_list) {412 struct nfs_page *subreq = destroy_list;···418 WARN_ON_ONCE(old_head != subreq->wb_head);419420 /* make sure old group is not used */421- subreq->wb_head = subreq;422 subreq->wb_this_page = subreq;00000000000000000423424 /* subreq is now totally disconnected from page group or any425 * write / commit lists. last chance to wake any waiters */426- nfs_unlock_request(subreq);427-428- if (!test_bit(PG_TEARDOWN, &subreq->wb_flags)) {429- /* release ref on old head request */430- nfs_release_request(old_head);431-432- nfs_page_group_clear_bits(subreq);433-434- /* release the PG_INODE_REF reference */435- if (test_and_clear_bit(PG_INODE_REF, &subreq->wb_flags))436- nfs_release_request(subreq);437- else438- WARN_ON_ONCE(1);439- } else {440- WARN_ON_ONCE(test_bit(PG_CLEAN, &subreq->wb_flags));441- /* zombie requests have already released the last442- * reference and were waiting on the rest of the443- * group to complete. Since it's no longer part of a444- * group, simply free the request */445- nfs_page_group_clear_bits(subreq);446- nfs_free_request(subreq);447- }448 }449}450···449 * operations for this page.450 *451 * @page - the page used to lookup the "page group" of nfs_page structures452- * @nonblock - if true, don't block waiting for request locks453 *454 * This function joins all sub requests to the head request by first455 * locking all requests in the group, cancelling any pending operations···462 * error was encountered.463 */464static struct nfs_page *465-nfs_lock_and_join_requests(struct page *page, bool nonblock)466{467 struct inode *inode = page_file_mapping(page)->host;468 struct nfs_page *head, *subreq;···471 int ret;472473try_again:474- total_bytes = 0;475-476- WARN_ON_ONCE(destroy_list);477-478- spin_lock(&inode->i_lock);479-480 /*481 * A reference is taken only on the head request which acts as a482 * reference to the whole page group - the group will not be destroyed483 * until the head reference is released.484 */485- head = nfs_page_find_head_request_locked(NFS_I(inode), page);486-487- if (!head) {488- spin_unlock(&inode->i_lock);489 return NULL;00000000490 }491492- /* holding inode lock, so always make a non-blocking call to try the493- * page group lock */494- ret = nfs_page_group_lock(head, true);0000495 if (ret < 0) {496- spin_unlock(&inode->i_lock);497-498- if (!nonblock && ret == -EAGAIN) {499- nfs_page_group_lock_wait(head);500- nfs_release_request(head);501- goto try_again;502- }503-504- nfs_release_request(head);505 return ERR_PTR(ret);506 }507508 /* lock each request in the page group */509- subreq = head;510- do {00000000000000000000511 /*512 * Subrequests are always contiguous, non overlapping513 * and in order - but may be repeated (mirrored writes).···534 } else if (WARN_ON_ONCE(subreq->wb_offset < head->wb_offset ||535 ((subreq->wb_offset + subreq->wb_bytes) >536 (head->wb_offset + total_bytes)))) {00537 nfs_page_group_unlock(head);538- spin_unlock(&inode->i_lock);539 return ERR_PTR(-EIO);540 }541-542- if (!nfs_lock_request(subreq)) {543- /* releases page group bit lock and544- * inode spin lock and all references */545- ret = nfs_unroll_locks_and_wait(inode, head,546- subreq, nonblock);547-548- if (ret == 0)549- goto try_again;550-551- return ERR_PTR(ret);552- }553-554- subreq = subreq->wb_this_page;555- } while (subreq != head);556557 /* Now that all requests are locked, make sure they aren't on any list.558 * Commit list removal accounting is done after locks are dropped */···561 head->wb_bytes = total_bytes;562 }563564- /*565- * prepare head request to be added to new pgio descriptor566- */567- nfs_page_group_clear_bits(head);568-569- /*570- * some part of the group was still on the inode list - otherwise571- * the group wouldn't be involved in async write.572- * grab a reference for the head request, iff it needs one.573- */574- if (!test_and_set_bit(PG_INODE_REF, &head->wb_flags))575 kref_get(&head->wb_kref);00576577 nfs_page_group_unlock(head);578579- /* drop lock to clean uprequests on destroy list */580- spin_unlock(&inode->i_lock);581582- nfs_destroy_unlinked_subrequests(destroy_list, head);0000583584- /* still holds ref on head from nfs_page_find_head_request_locked585 * and still has lock on head from lock loop */586 return head;587}588589static void nfs_write_error_remove_page(struct nfs_page *req)590{591- nfs_unlock_request(req);592 nfs_end_page_writeback(req);593 generic_error_remove_page(page_file_mapping(req->wb_page),594 req->wb_page);···608 * May return an error if the user signalled nfs_wait_on_request().609 */610static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,611- struct page *page, bool nonblock)612{613 struct nfs_page *req;614 int ret = 0;615616- req = nfs_lock_and_join_requests(page, nonblock);617 if (!req)618 goto out;619 ret = PTR_ERR(req);···656 int ret;657658 nfs_pageio_cond_complete(pgio, page_index(page));659- ret = nfs_page_async_flush(pgio, page, wbc->sync_mode == WB_SYNC_NONE);660 if (ret == -EAGAIN) {661 redirty_page_for_writepage(wbc, page);662 ret = 0;···743 */744static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req)745{0746 struct nfs_inode *nfsi = NFS_I(inode);747748 WARN_ON_ONCE(req->wb_this_page != req);···751 /* Lock the request! */752 nfs_lock_request(req);753754- spin_lock(&inode->i_lock);755- if (!nfsi->nrequests &&756- NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE))757- inode->i_version++;758 /*759 * Swap-space should not get truncated. Hence no need to plug the race760 * with invalidate/truncate.761 */0000000762 if (likely(!PageSwapCache(req->wb_page))) {763 set_bit(PG_MAPPED, &req->wb_flags);764 SetPagePrivate(req->wb_page);765 set_page_private(req->wb_page, (unsigned long)req);766 }767- nfsi->nrequests++;0768 /* this a head request for a page group - mark it as having an769 * extra reference so sub groups can follow suit.770 * This flag also informs pgio layer when to bump nrequests when771 * adding subrequests. */772 WARN_ON(test_and_set_bit(PG_INODE_REF, &req->wb_flags));773 kref_get(&req->wb_kref);774- spin_unlock(&inode->i_lock);775}776777/*···782 */783static void nfs_inode_remove_request(struct nfs_page *req)784{785- struct inode *inode = d_inode(req->wb_context->dentry);0786 struct nfs_inode *nfsi = NFS_I(inode);787 struct nfs_page *head;7880789 if (nfs_page_group_sync_on_bit(req, PG_REMOVE)) {790 head = req->wb_head;791792- spin_lock(&inode->i_lock);793 if (likely(head->wb_page && !PageSwapCache(head->wb_page))) {794 set_page_private(head->wb_page, 0);795 ClearPagePrivate(head->wb_page);796 clear_bit(PG_MAPPED, &head->wb_flags);797 }798- nfsi->nrequests--;799- spin_unlock(&inode->i_lock);800- } else {801- spin_lock(&inode->i_lock);802- nfsi->nrequests--;803- spin_unlock(&inode->i_lock);804 }805806 if (test_and_clear_bit(PG_INODE_REF, &req->wb_flags))···853 * number of outstanding requests requiring a commit as well as854 * the MM page stats.855 *856- * The caller must hold cinfo->inode->i_lock, and the nfs_page lock.0857 */858void859nfs_request_add_commit_list_locked(struct nfs_page *req, struct list_head *dst,···862{863 set_bit(PG_CLEAN, &req->wb_flags);864 nfs_list_add_request(req, dst);865- cinfo->mds->ncommit++;866}867EXPORT_SYMBOL_GPL(nfs_request_add_commit_list_locked);868···882void883nfs_request_add_commit_list(struct nfs_page *req, struct nfs_commit_info *cinfo)884{885- spin_lock(&cinfo->inode->i_lock);886 nfs_request_add_commit_list_locked(req, &cinfo->mds->list, cinfo);887- spin_unlock(&cinfo->inode->i_lock);888 if (req->wb_page)889 nfs_mark_page_unstable(req->wb_page, cinfo);890}···908 if (!test_and_clear_bit(PG_CLEAN, &(req)->wb_flags))909 return;910 nfs_list_remove_request(req);911- cinfo->mds->ncommit--;912}913EXPORT_SYMBOL_GPL(nfs_request_remove_commit_list);914···953 WB_RECLAIMABLE);954}955956-/* Called holding inode (/cinfo) lock */957static void958nfs_clear_request_commit(struct nfs_page *req)959{···962 struct nfs_commit_info cinfo;963964 nfs_init_cinfo_from_inode(&cinfo, inode);0965 if (!pnfs_clear_request_commit(req, &cinfo)) {966 nfs_request_remove_commit_list(req, &cinfo);967 }0968 nfs_clear_page_commit(req->wb_page);969 }970}···1011remove_req:1012 nfs_inode_remove_request(req);1013next:1014- nfs_unlock_request(req);1015 nfs_end_page_writeback(req);1016 nfs_release_request(req);1017 }···1022unsigned long1023nfs_reqs_to_commit(struct nfs_commit_info *cinfo)1024{1025- return cinfo->mds->ncommit;1026}10271028-/* cinfo->inode->i_lock held by caller */1029int1030nfs_scan_commit_list(struct list_head *src, struct list_head *dst,1031 struct nfs_commit_info *cinfo, int max)1032{1033- struct nfs_page *req, *tmp;1034 int ret = 0;10351036- list_for_each_entry_safe(req, tmp, src, wb_list) {1037- if (!nfs_lock_request(req))1038- continue;1039 kref_get(&req->wb_kref);1040- if (cond_resched_lock(&cinfo->inode->i_lock))1041- list_safe_reset_next(req, tmp, wb_list);000000001042 nfs_request_remove_commit_list(req, cinfo);1043 nfs_list_add_request(req, dst);1044 ret++;1045 if ((ret == max) && !cinfo->dreq)1046 break;01047 }1048 return ret;1049}···1071{1072 int ret = 0;10731074- spin_lock(&cinfo->inode->i_lock);1075- if (cinfo->mds->ncommit > 0) {001076 const int max = INT_MAX;10771078 ret = nfs_scan_commit_list(&cinfo->mds->list, dst,1079 cinfo, max);1080 ret += pnfs_scan_commit_lists(inode, cinfo, max - ret);1081 }1082- spin_unlock(&cinfo->inode->i_lock);1083 return ret;1084}1085···1102 unsigned int end;1103 int error;11041105- if (!PagePrivate(page))1106- return NULL;1107-1108 end = offset + bytes;1109- spin_lock(&inode->i_lock);11101111- for (;;) {1112- req = nfs_page_find_head_request_locked(NFS_I(inode), page);1113- if (req == NULL)1114- goto out_unlock;11151116- /* should be handled by nfs_flush_incompatible */1117- WARN_ON_ONCE(req->wb_head != req);1118- WARN_ON_ONCE(req->wb_this_page != req);1119-1120- rqend = req->wb_offset + req->wb_bytes;1121- /*1122- * Tell the caller to flush out the request if1123- * the offsets are non-contiguous.1124- * Note: nfs_flush_incompatible() will already1125- * have flushed out requests having wrong owners.1126- */1127- if (offset > rqend1128- || end < req->wb_offset)1129- goto out_flushme;1130-1131- if (nfs_lock_request(req))1132- break;1133-1134- /* The request is locked, so wait and then retry */1135- spin_unlock(&inode->i_lock);1136- error = nfs_wait_on_request(req);1137- nfs_release_request(req);1138- if (error != 0)1139- goto out_err;1140- spin_lock(&inode->i_lock);1141- }11421143 /* Okay, the request matches. Update the region */1144 if (offset < req->wb_offset) {···1127 req->wb_bytes = end - req->wb_offset;1128 else1129 req->wb_bytes = rqend - req->wb_offset;1130-out_unlock:1131- if (req)1132- nfs_clear_request_commit(req);1133- spin_unlock(&inode->i_lock);1134 return req;1135out_flushme:1136- spin_unlock(&inode->i_lock);1137- nfs_release_request(req);000001138 error = nfs_wb_page(inode, page);1139-out_err:1140- return ERR_PTR(error);1141}11421143/*···1202 l_ctx = req->wb_lock_context;1203 do_flush = req->wb_page != page ||1204 !nfs_match_open_context(req->wb_context, ctx);1205- /* for now, flush if more than 1 request in page_group */1206- do_flush |= req->wb_this_page != req;1207 if (l_ctx && flctx &&1208 !(list_empty_careful(&flctx->flc_posix) &&1209 list_empty_careful(&flctx->flc_flock))) {···1385{1386 nfs_mark_request_dirty(req);1387 set_bit(NFS_CONTEXT_RESEND_WRITES, &req->wb_context->flags);1388- nfs_unlock_request(req);1389 nfs_end_page_writeback(req);1390 nfs_release_request(req);1391}···1906 int ret = 0;19071908 /* no commits means nothing needs to be done */1909- if (!nfsi->commit_info.ncommit)1910 return ret;19111912 if (wbc->sync_mode == WB_SYNC_NONE) {···19871988 /* blocking call to cancel all requests and join to a single (head)1989 * request */1990- req = nfs_lock_and_join_requests(page, false);19911992 if (IS_ERR(req)) {1993 ret = PTR_ERR(req);
···154 set_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);155}156157+static struct nfs_page *158+nfs_page_private_request(struct page *page)159+{160+ if (!PagePrivate(page))161+ return NULL;162+ return (struct nfs_page *)page_private(page);163+}164+165/*166 * nfs_page_find_head_request_locked - find head request associated with @page167 *···162 * returns matching head request with reference held, or NULL if not found.163 */164static struct nfs_page *165+nfs_page_find_private_request(struct page *page)166{167+ struct address_space *mapping = page_file_mapping(page);168+ struct nfs_page *req;169170+ if (!PagePrivate(page))171+ return NULL;172+ spin_lock(&mapping->private_lock);173+ req = nfs_page_private_request(page);00174 if (req) {175 WARN_ON_ONCE(req->wb_head != req);176 kref_get(&req->wb_kref);177 }178+ spin_unlock(&mapping->private_lock);179+ return req;180+}181182+static struct nfs_page *183+nfs_page_find_swap_request(struct page *page)184+{185+ struct inode *inode = page_file_mapping(page)->host;186+ struct nfs_inode *nfsi = NFS_I(inode);187+ struct nfs_page *req = NULL;188+ if (!PageSwapCache(page))189+ return NULL;190+ mutex_lock(&nfsi->commit_mutex);191+ if (PageSwapCache(page)) {192+ req = nfs_page_search_commits_for_head_request_locked(nfsi,193+ page);194+ if (req) {195+ WARN_ON_ONCE(req->wb_head != req);196+ kref_get(&req->wb_kref);197+ }198+ }199+ mutex_unlock(&nfsi->commit_mutex);200 return req;201}202···187 */188static struct nfs_page *nfs_page_find_head_request(struct page *page)189{190+ struct nfs_page *req;0191192+ req = nfs_page_find_private_request(page);193+ if (!req)194+ req = nfs_page_find_swap_request(page);195 return req;196}197···241{242 struct nfs_page *req;243000244 req = head;245 do {246 if (page_offset >= req->wb_pgbase &&···269 unsigned int pos = 0;270 unsigned int len = nfs_page_length(req->wb_page);271272+ nfs_page_group_lock(req);273274+ for (;;) {275 tmp = nfs_page_group_search_locked(req->wb_head, pos);276+ if (!tmp)277+ break;278+ pos = tmp->wb_pgbase + tmp->wb_bytes;279+ }00280281 nfs_page_group_unlock(req);282+ return pos >= len;0283}284285/* We can set the PG_uptodate flag if we see that a write request···333{334 struct inode *inode = page_file_mapping(req->wb_page)->host;335 struct nfs_server *nfss = NFS_SERVER(inode);336+ bool is_done;337338+ is_done = nfs_page_group_sync_on_bit(req, PG_WB_END);339+ nfs_unlock_request(req);340+ if (!is_done)341 return;342343 end_page_writeback(req->wb_page);344 if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH)345 clear_bdi_congested(inode_to_bdi(inode), BLK_RW_ASYNC);346}0000000000000000347348/*349 * nfs_unroll_locks_and_wait - unlock all newly locked reqs and wait on @req···366 * @inode - inode associated with request page group, must be holding inode lock367 * @head - head request of page group, must be holding head lock368 * @req - request that couldn't lock and needs to wait on the req bit lock0369 *370+ * NOTE: this must be called holding page_group bit lock371+ * which will be released before returning.372 *373 * returns 0 on success, < 0 on error.374 */375+static void376+nfs_unroll_locks(struct inode *inode, struct nfs_page *head,377+ struct nfs_page *req)0378{379 struct nfs_page *tmp;0380381 /* relinquish all the locks successfully grabbed this run */382+ for (tmp = head->wb_this_page ; tmp != req; tmp = tmp->wb_this_page) {383+ if (!kref_read(&tmp->wb_kref))384+ continue;385+ nfs_unlock_and_release_request(tmp);386+ }0000000000000000387}388389/*···417 */418static void419nfs_destroy_unlinked_subrequests(struct nfs_page *destroy_list,420+ struct nfs_page *old_head,421+ struct inode *inode)422{423 while (destroy_list) {424 struct nfs_page *subreq = destroy_list;···428 WARN_ON_ONCE(old_head != subreq->wb_head);429430 /* make sure old group is not used */0431 subreq->wb_this_page = subreq;432+433+ clear_bit(PG_REMOVE, &subreq->wb_flags);434+435+ /* Note: races with nfs_page_group_destroy() */436+ if (!kref_read(&subreq->wb_kref)) {437+ /* Check if we raced with nfs_page_group_destroy() */438+ if (test_and_clear_bit(PG_TEARDOWN, &subreq->wb_flags))439+ nfs_free_request(subreq);440+ continue;441+ }442+443+ subreq->wb_head = subreq;444+445+ if (test_and_clear_bit(PG_INODE_REF, &subreq->wb_flags)) {446+ nfs_release_request(subreq);447+ atomic_long_dec(&NFS_I(inode)->nrequests);448+ }449450 /* subreq is now totally disconnected from page group or any451 * write / commit lists. last chance to wake any waiters */452+ nfs_unlock_and_release_request(subreq);000000000000000000000453 }454}455···464 * operations for this page.465 *466 * @page - the page used to lookup the "page group" of nfs_page structures0467 *468 * This function joins all sub requests to the head request by first469 * locking all requests in the group, cancelling any pending operations···478 * error was encountered.479 */480static struct nfs_page *481+nfs_lock_and_join_requests(struct page *page)482{483 struct inode *inode = page_file_mapping(page)->host;484 struct nfs_page *head, *subreq;···487 int ret;488489try_again:000000490 /*491 * A reference is taken only on the head request which acts as a492 * reference to the whole page group - the group will not be destroyed493 * until the head reference is released.494 */495+ head = nfs_page_find_head_request(page);496+ if (!head)00497 return NULL;498+499+ /* lock the page head first in order to avoid an ABBA inefficiency */500+ if (!nfs_lock_request(head)) {501+ ret = nfs_wait_on_request(head);502+ nfs_release_request(head);503+ if (ret < 0)504+ return ERR_PTR(ret);505+ goto try_again;506 }507508+ /* Ensure that nobody removed the request before we locked it */509+ if (head != nfs_page_private_request(page) && !PageSwapCache(page)) {510+ nfs_unlock_and_release_request(head);511+ goto try_again;512+ }513+514+ ret = nfs_page_group_lock(head);515 if (ret < 0) {516+ nfs_unlock_and_release_request(head);00000000517 return ERR_PTR(ret);518 }519520 /* lock each request in the page group */521+ total_bytes = head->wb_bytes;522+ for (subreq = head->wb_this_page; subreq != head;523+ subreq = subreq->wb_this_page) {524+525+ if (!kref_get_unless_zero(&subreq->wb_kref))526+ continue;527+ while (!nfs_lock_request(subreq)) {528+ /*529+ * Unlock page to allow nfs_page_group_sync_on_bit()530+ * to succeed531+ */532+ nfs_page_group_unlock(head);533+ ret = nfs_wait_on_request(subreq);534+ if (!ret)535+ ret = nfs_page_group_lock(head);536+ if (ret < 0) {537+ nfs_unroll_locks(inode, head, subreq);538+ nfs_release_request(subreq);539+ nfs_unlock_and_release_request(head);540+ return ERR_PTR(ret);541+ }542+ }543 /*544 * Subrequests are always contiguous, non overlapping545 * and in order - but may be repeated (mirrored writes).···534 } else if (WARN_ON_ONCE(subreq->wb_offset < head->wb_offset ||535 ((subreq->wb_offset + subreq->wb_bytes) >536 (head->wb_offset + total_bytes)))) {537+ nfs_unroll_locks(inode, head, subreq);538+ nfs_unlock_and_release_request(subreq);539 nfs_page_group_unlock(head);540+ nfs_unlock_and_release_request(head);541 return ERR_PTR(-EIO);542 }543+ }00000000000000544545 /* Now that all requests are locked, make sure they aren't on any list.546 * Commit list removal accounting is done after locks are dropped */···573 head->wb_bytes = total_bytes;574 }575576+ /* Postpone destruction of this request */577+ if (test_and_clear_bit(PG_REMOVE, &head->wb_flags)) {578+ set_bit(PG_INODE_REF, &head->wb_flags);00000000579 kref_get(&head->wb_kref);580+ atomic_long_inc(&NFS_I(inode)->nrequests);581+ }582583 nfs_page_group_unlock(head);584585+ nfs_destroy_unlinked_subrequests(destroy_list, head, inode);0586587+ /* Did we lose a race with nfs_inode_remove_request()? */588+ if (!(PagePrivate(page) || PageSwapCache(page))) {589+ nfs_unlock_and_release_request(head);590+ return NULL;591+ }592593+ /* still holds ref on head from nfs_page_find_head_request594 * and still has lock on head from lock loop */595 return head;596}597598static void nfs_write_error_remove_page(struct nfs_page *req)599{0600 nfs_end_page_writeback(req);601 generic_error_remove_page(page_file_mapping(req->wb_page),602 req->wb_page);···624 * May return an error if the user signalled nfs_wait_on_request().625 */626static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,627+ struct page *page)628{629 struct nfs_page *req;630 int ret = 0;631632+ req = nfs_lock_and_join_requests(page);633 if (!req)634 goto out;635 ret = PTR_ERR(req);···672 int ret;673674 nfs_pageio_cond_complete(pgio, page_index(page));675+ ret = nfs_page_async_flush(pgio, page);676 if (ret == -EAGAIN) {677 redirty_page_for_writepage(wbc, page);678 ret = 0;···759 */760static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req)761{762+ struct address_space *mapping = page_file_mapping(req->wb_page);763 struct nfs_inode *nfsi = NFS_I(inode);764765 WARN_ON_ONCE(req->wb_this_page != req);···766 /* Lock the request! */767 nfs_lock_request(req);7680000769 /*770 * Swap-space should not get truncated. Hence no need to plug the race771 * with invalidate/truncate.772 */773+ spin_lock(&mapping->private_lock);774+ if (!nfs_have_writebacks(inode) &&775+ NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE)) {776+ spin_lock(&inode->i_lock);777+ inode->i_version++;778+ spin_unlock(&inode->i_lock);779+ }780 if (likely(!PageSwapCache(req->wb_page))) {781 set_bit(PG_MAPPED, &req->wb_flags);782 SetPagePrivate(req->wb_page);783 set_page_private(req->wb_page, (unsigned long)req);784 }785+ spin_unlock(&mapping->private_lock);786+ atomic_long_inc(&nfsi->nrequests);787 /* this a head request for a page group - mark it as having an788 * extra reference so sub groups can follow suit.789 * This flag also informs pgio layer when to bump nrequests when790 * adding subrequests. */791 WARN_ON(test_and_set_bit(PG_INODE_REF, &req->wb_flags));792 kref_get(&req->wb_kref);0793}794795/*···794 */795static void nfs_inode_remove_request(struct nfs_page *req)796{797+ struct address_space *mapping = page_file_mapping(req->wb_page);798+ struct inode *inode = mapping->host;799 struct nfs_inode *nfsi = NFS_I(inode);800 struct nfs_page *head;801802+ atomic_long_dec(&nfsi->nrequests);803 if (nfs_page_group_sync_on_bit(req, PG_REMOVE)) {804 head = req->wb_head;805806+ spin_lock(&mapping->private_lock);807 if (likely(head->wb_page && !PageSwapCache(head->wb_page))) {808 set_page_private(head->wb_page, 0);809 ClearPagePrivate(head->wb_page);810 clear_bit(PG_MAPPED, &head->wb_flags);811 }812+ spin_unlock(&mapping->private_lock);00000813 }814815 if (test_and_clear_bit(PG_INODE_REF, &req->wb_flags))···868 * number of outstanding requests requiring a commit as well as869 * the MM page stats.870 *871+ * The caller must hold NFS_I(cinfo->inode)->commit_mutex, and the872+ * nfs_page lock.873 */874void875nfs_request_add_commit_list_locked(struct nfs_page *req, struct list_head *dst,···876{877 set_bit(PG_CLEAN, &req->wb_flags);878 nfs_list_add_request(req, dst);879+ atomic_long_inc(&cinfo->mds->ncommit);880}881EXPORT_SYMBOL_GPL(nfs_request_add_commit_list_locked);882···896void897nfs_request_add_commit_list(struct nfs_page *req, struct nfs_commit_info *cinfo)898{899+ mutex_lock(&NFS_I(cinfo->inode)->commit_mutex);900 nfs_request_add_commit_list_locked(req, &cinfo->mds->list, cinfo);901+ mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);902 if (req->wb_page)903 nfs_mark_page_unstable(req->wb_page, cinfo);904}···922 if (!test_and_clear_bit(PG_CLEAN, &(req)->wb_flags))923 return;924 nfs_list_remove_request(req);925+ atomic_long_dec(&cinfo->mds->ncommit);926}927EXPORT_SYMBOL_GPL(nfs_request_remove_commit_list);928···967 WB_RECLAIMABLE);968}969970+/* Called holding the request lock on @req */971static void972nfs_clear_request_commit(struct nfs_page *req)973{···976 struct nfs_commit_info cinfo;977978 nfs_init_cinfo_from_inode(&cinfo, inode);979+ mutex_lock(&NFS_I(inode)->commit_mutex);980 if (!pnfs_clear_request_commit(req, &cinfo)) {981 nfs_request_remove_commit_list(req, &cinfo);982 }983+ mutex_unlock(&NFS_I(inode)->commit_mutex);984 nfs_clear_page_commit(req->wb_page);985 }986}···1023remove_req:1024 nfs_inode_remove_request(req);1025next:01026 nfs_end_page_writeback(req);1027 nfs_release_request(req);1028 }···1035unsigned long1036nfs_reqs_to_commit(struct nfs_commit_info *cinfo)1037{1038+ return atomic_long_read(&cinfo->mds->ncommit);1039}10401041+/* NFS_I(cinfo->inode)->commit_mutex held by caller */1042int1043nfs_scan_commit_list(struct list_head *src, struct list_head *dst,1044 struct nfs_commit_info *cinfo, int max)1045{1046+ struct nfs_page *req;1047 int ret = 0;10481049+ while(!list_empty(src)) {1050+ req = list_first_entry(src, struct nfs_page, wb_list);01051 kref_get(&req->wb_kref);1052+ if (!nfs_lock_request(req)) {1053+ int status;1054+ mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);1055+ status = nfs_wait_on_request(req);1056+ nfs_release_request(req);1057+ mutex_lock(&NFS_I(cinfo->inode)->commit_mutex);1058+ if (status < 0)1059+ break;1060+ continue;1061+ }1062 nfs_request_remove_commit_list(req, cinfo);1063 nfs_list_add_request(req, dst);1064 ret++;1065 if ((ret == max) && !cinfo->dreq)1066 break;1067+ cond_resched();1068 }1069 return ret;1070}···1076{1077 int ret = 0;10781079+ if (!atomic_long_read(&cinfo->mds->ncommit))1080+ return 0;1081+ mutex_lock(&NFS_I(cinfo->inode)->commit_mutex);1082+ if (atomic_long_read(&cinfo->mds->ncommit) > 0) {1083 const int max = INT_MAX;10841085 ret = nfs_scan_commit_list(&cinfo->mds->list, dst,1086 cinfo, max);1087 ret += pnfs_scan_commit_lists(inode, cinfo, max - ret);1088 }1089+ mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);1090 return ret;1091}1092···1105 unsigned int end;1106 int error;11070001108 end = offset + bytes;011091110+ req = nfs_lock_and_join_requests(page);1111+ if (IS_ERR_OR_NULL(req))1112+ return req;011131114+ rqend = req->wb_offset + req->wb_bytes;1115+ /*1116+ * Tell the caller to flush out the request if1117+ * the offsets are non-contiguous.1118+ * Note: nfs_flush_incompatible() will already1119+ * have flushed out requests having wrong owners.1120+ */1121+ if (offset > rqend || end < req->wb_offset)1122+ goto out_flushme;0000000000000000011231124 /* Okay, the request matches. Update the region */1125 if (offset < req->wb_offset) {···1152 req->wb_bytes = end - req->wb_offset;1153 else1154 req->wb_bytes = rqend - req->wb_offset;00001155 return req;1156out_flushme:1157+ /*1158+ * Note: we mark the request dirty here because1159+ * nfs_lock_and_join_requests() cannot preserve1160+ * commit flags, so we have to replay the write.1161+ */1162+ nfs_mark_request_dirty(req);1163+ nfs_unlock_and_release_request(req);1164 error = nfs_wb_page(inode, page);1165+ return (error < 0) ? ERR_PTR(error) : NULL;01166}11671168/*···1227 l_ctx = req->wb_lock_context;1228 do_flush = req->wb_page != page ||1229 !nfs_match_open_context(req->wb_context, ctx);001230 if (l_ctx && flctx &&1231 !(list_empty_careful(&flctx->flc_posix) &&1232 list_empty_careful(&flctx->flc_flock))) {···1412{1413 nfs_mark_request_dirty(req);1414 set_bit(NFS_CONTEXT_RESEND_WRITES, &req->wb_context->flags);01415 nfs_end_page_writeback(req);1416 nfs_release_request(req);1417}···1934 int ret = 0;19351936 /* no commits means nothing needs to be done */1937+ if (!atomic_long_read(&nfsi->commit_info.ncommit))1938 return ret;19391940 if (wbc->sync_mode == WB_SYNC_NONE) {···20152016 /* blocking call to cancel all requests and join to a single (head)2017 * request */2018+ req = nfs_lock_and_join_requests(page);20192020 if (IS_ERR(req)) {2021 ret = PTR_ERR(req);
···844}845EXPORT_SYMBOL_GPL(xprt_lookup_rqst);846000000000000000000000000000000000000000000847static void xprt_update_rtt(struct rpc_task *task)848{849 struct rpc_rqst *req = task->tk_rqstp;···1008 /*1009 * Add to the list only if we're expecting a reply1010 */1011- spin_lock_bh(&xprt->transport_lock);1012 /* Update the softirq receive buffer */1013 memcpy(&req->rq_private_buf, &req->rq_rcv_buf,1014 sizeof(req->rq_private_buf));1015 /* Add request to the receive list */01016 list_add_tail(&req->rq_list, &xprt->recv);1017- spin_unlock_bh(&xprt->transport_lock);1018 xprt_reset_majortimeo(req);1019 /* Turn off autodisconnect */1020 del_singleshot_timer_sync(&xprt->timer);···1329 task->tk_ops->rpc_count_stats(task, task->tk_calldata);1330 else if (task->tk_client)1331 rpc_count_iostats(task, task->tk_client->cl_metrics);0000001332 spin_lock_bh(&xprt->transport_lock);1333 xprt->ops->release_xprt(xprt, task);1334 if (xprt->ops->release_request)1335 xprt->ops->release_request(task);1336- if (!list_empty(&req->rq_list))1337- list_del(&req->rq_list);1338 xprt->last_used = jiffies;1339 xprt_schedule_autodisconnect(xprt);1340 spin_unlock_bh(&xprt->transport_lock);···13641365 spin_lock_init(&xprt->transport_lock);1366 spin_lock_init(&xprt->reserve_lock);013671368 INIT_LIST_HEAD(&xprt->free);1369 INIT_LIST_HEAD(&xprt->recv);
···844}845EXPORT_SYMBOL_GPL(xprt_lookup_rqst);846847+/**848+ * xprt_pin_rqst - Pin a request on the transport receive list849+ * @req: Request to pin850+ *851+ * Caller must ensure this is atomic with the call to xprt_lookup_rqst()852+ * so should be holding the xprt transport lock.853+ */854+void xprt_pin_rqst(struct rpc_rqst *req)855+{856+ set_bit(RPC_TASK_MSG_RECV, &req->rq_task->tk_runstate);857+}858+859+/**860+ * xprt_unpin_rqst - Unpin a request on the transport receive list861+ * @req: Request to pin862+ *863+ * Caller should be holding the xprt transport lock.864+ */865+void xprt_unpin_rqst(struct rpc_rqst *req)866+{867+ struct rpc_task *task = req->rq_task;868+869+ clear_bit(RPC_TASK_MSG_RECV, &task->tk_runstate);870+ if (test_bit(RPC_TASK_MSG_RECV_WAIT, &task->tk_runstate))871+ wake_up_bit(&task->tk_runstate, RPC_TASK_MSG_RECV);872+}873+874+static void xprt_wait_on_pinned_rqst(struct rpc_rqst *req)875+__must_hold(&req->rq_xprt->recv_lock)876+{877+ struct rpc_task *task = req->rq_task;878+879+ if (task && test_bit(RPC_TASK_MSG_RECV, &task->tk_runstate)) {880+ spin_unlock(&req->rq_xprt->recv_lock);881+ set_bit(RPC_TASK_MSG_RECV_WAIT, &task->tk_runstate);882+ wait_on_bit(&task->tk_runstate, RPC_TASK_MSG_RECV,883+ TASK_UNINTERRUPTIBLE);884+ clear_bit(RPC_TASK_MSG_RECV_WAIT, &task->tk_runstate);885+ spin_lock(&req->rq_xprt->recv_lock);886+ }887+}888+889static void xprt_update_rtt(struct rpc_task *task)890{891 struct rpc_rqst *req = task->tk_rqstp;···966 /*967 * Add to the list only if we're expecting a reply968 */0969 /* Update the softirq receive buffer */970 memcpy(&req->rq_private_buf, &req->rq_rcv_buf,971 sizeof(req->rq_private_buf));972 /* Add request to the receive list */973+ spin_lock(&xprt->recv_lock);974 list_add_tail(&req->rq_list, &xprt->recv);975+ spin_unlock(&xprt->recv_lock);976 xprt_reset_majortimeo(req);977 /* Turn off autodisconnect */978 del_singleshot_timer_sync(&xprt->timer);···1287 task->tk_ops->rpc_count_stats(task, task->tk_calldata);1288 else if (task->tk_client)1289 rpc_count_iostats(task, task->tk_client->cl_metrics);1290+ spin_lock(&xprt->recv_lock);1291+ if (!list_empty(&req->rq_list)) {1292+ list_del(&req->rq_list);1293+ xprt_wait_on_pinned_rqst(req);1294+ }1295+ spin_unlock(&xprt->recv_lock);1296 spin_lock_bh(&xprt->transport_lock);1297 xprt->ops->release_xprt(xprt, task);1298 if (xprt->ops->release_request)1299 xprt->ops->release_request(task);001300 xprt->last_used = jiffies;1301 xprt_schedule_autodisconnect(xprt);1302 spin_unlock_bh(&xprt->transport_lock);···13181319 spin_lock_init(&xprt->transport_lock);1320 spin_lock_init(&xprt->reserve_lock);1321+ spin_lock_init(&xprt->recv_lock);13221323 INIT_LIST_HEAD(&xprt->free);1324 INIT_LIST_HEAD(&xprt->recv);
+4-4
net/sunrpc/xprtrdma/rpc_rdma.c
···1051 * RPC completion while holding the transport lock to ensure1052 * the rep, rqst, and rq_task pointers remain stable.1053 */1054- spin_lock_bh(&xprt->transport_lock);1055 rqst = xprt_lookup_rqst(xprt, headerp->rm_xid);1056 if (!rqst)1057 goto out_norqst;···1136 xprt_release_rqst_cong(rqst->rq_task);11371138 xprt_complete_rqst(rqst->rq_task, status);1139- spin_unlock_bh(&xprt->transport_lock);1140 dprintk("RPC: %s: xprt_complete_rqst(0x%p, 0x%p, %d)\n",1141 __func__, xprt, rqst, status);1142 return;···1187 r_xprt->rx_stats.bad_reply_count++;1188 goto out;11891190-/* The req was still available, but by the time the transport_lock1191 * was acquired, the rqst and task had been released. Thus the RPC1192 * has already been terminated.1193 */1194out_norqst:1195- spin_unlock_bh(&xprt->transport_lock);1196 rpcrdma_buffer_put(req);1197 dprintk("RPC: %s: race, no rqst left for req %p\n",1198 __func__, req);
···1051 * RPC completion while holding the transport lock to ensure1052 * the rep, rqst, and rq_task pointers remain stable.1053 */1054+ spin_lock(&xprt->recv_lock);1055 rqst = xprt_lookup_rqst(xprt, headerp->rm_xid);1056 if (!rqst)1057 goto out_norqst;···1136 xprt_release_rqst_cong(rqst->rq_task);11371138 xprt_complete_rqst(rqst->rq_task, status);1139+ spin_unlock(&xprt->recv_lock);1140 dprintk("RPC: %s: xprt_complete_rqst(0x%p, 0x%p, %d)\n",1141 __func__, xprt, rqst, status);1142 return;···1187 r_xprt->rx_stats.bad_reply_count++;1188 goto out;11891190+/* The req was still available, but by the time the recv_lock1191 * was acquired, the rqst and task had been released. Thus the RPC1192 * has already been terminated.1193 */1194out_norqst:1195+ spin_unlock(&xprt->recv_lock);1196 rpcrdma_buffer_put(req);1197 dprintk("RPC: %s: race, no rqst left for req %p\n",1198 __func__, req);
+5-2
net/sunrpc/xprtrdma/svc_rdma_backchannel.c
···52 if (src->iov_len < 24)53 goto out_shortreply;5455- spin_lock_bh(&xprt->transport_lock);56 req = xprt_lookup_rqst(xprt, xid);57 if (!req)58 goto out_notfound;···69 else if (credits > r_xprt->rx_buf.rb_bc_max_requests)70 credits = r_xprt->rx_buf.rb_bc_max_requests;71072 cwnd = xprt->cwnd;73 xprt->cwnd = credits << RPC_CWNDSHIFT;74 if (xprt->cwnd > cwnd)75 xprt_release_rqst_cong(req->rq_task);007677 ret = 0;78 xprt_complete_rqst(req->rq_task, rcvbuf->len);79 rcvbuf->len = 0;8081out_unlock:82- spin_unlock_bh(&xprt->transport_lock);83out:84 return ret;85
···52 if (src->iov_len < 24)53 goto out_shortreply;5455+ spin_lock(&xprt->recv_lock);56 req = xprt_lookup_rqst(xprt, xid);57 if (!req)58 goto out_notfound;···69 else if (credits > r_xprt->rx_buf.rb_bc_max_requests)70 credits = r_xprt->rx_buf.rb_bc_max_requests;7172+ spin_lock_bh(&xprt->transport_lock);73 cwnd = xprt->cwnd;74 xprt->cwnd = credits << RPC_CWNDSHIFT;75 if (xprt->cwnd > cwnd)76 xprt_release_rqst_cong(req->rq_task);77+ spin_unlock_bh(&xprt->transport_lock);78+7980 ret = 0;81 xprt_complete_rqst(req->rq_task, rcvbuf->len);82 rcvbuf->len = 0;8384out_unlock:85+ spin_unlock(&xprt->recv_lock);86out:87 return ret;88
+44-40
net/sunrpc/xprtsock.c
···969 return;970971 /* Look up and lock the request corresponding to the given XID */972- spin_lock_bh(&xprt->transport_lock);973 rovr = xprt_lookup_rqst(xprt, *xp);974 if (!rovr)975 goto out_unlock;00976 task = rovr->rq_task;977978 copied = rovr->rq_private_buf.buflen;···983984 if (xs_local_copy_to_xdr(&rovr->rq_private_buf, skb)) {985 dprintk("RPC: sk_buff copy failed\n");986- goto out_unlock;0987 }9880989 xprt_complete_rqst(task, copied);990-0991 out_unlock:992- spin_unlock_bh(&xprt->transport_lock);993}994995static void xs_local_data_receive(struct sock_xprt *transport)···1055 return;10561057 /* Look up and lock the request corresponding to the given XID */1058- spin_lock_bh(&xprt->transport_lock);1059 rovr = xprt_lookup_rqst(xprt, *xp);1060 if (!rovr)1061 goto out_unlock;001062 task = rovr->rq_task;10631064 if ((copied = rovr->rq_private_buf.buflen) > repsize)···1069 /* Suck it into the iovec, verify checksum if not done by hw. */1070 if (csum_partial_copy_to_xdr(&rovr->rq_private_buf, skb)) {1071 __UDPX_INC_STATS(sk, UDP_MIB_INERRORS);1072- goto out_unlock;01073 }10741075 __UDPX_INC_STATS(sk, UDP_MIB_INDATAGRAMS);107601077 xprt_adjust_cwnd(xprt, task, copied);1078- xprt_complete_rqst(task, copied);1079-1080- out_unlock:1081 spin_unlock_bh(&xprt->transport_lock);0000001082}10831084static void xs_udp_data_receive(struct sock_xprt *transport)···1289 }12901291 len = desc->count;1292- if (len > transport->tcp_reclen - transport->tcp_offset) {1293- struct xdr_skb_reader my_desc;1294-1295- len = transport->tcp_reclen - transport->tcp_offset;1296- memcpy(&my_desc, desc, sizeof(my_desc));1297- my_desc.count = len;1298- r = xdr_partial_copy_from_skb(rcvbuf, transport->tcp_copied,1299- &my_desc, xdr_skb_read_bits);1300- desc->count -= r;1301- desc->offset += r;1302- } else1303- r = xdr_partial_copy_from_skb(rcvbuf, transport->tcp_copied,1304 desc, xdr_skb_read_bits);13051306- if (r > 0) {1307- transport->tcp_copied += r;1308- transport->tcp_offset += r;1309- }1310- if (r != len) {1311 /* Error when copying to the receive buffer,1312 * usually because we weren't able to allocate1313 * additional buffer pages. All we can do now···1313 transport->tcp_offset, transport->tcp_reclen);1314 return;1315 }000013161317 dprintk("RPC: XID %08x read %zd bytes\n",1318 ntohl(transport->tcp_xid), r);···1346 dprintk("RPC: read reply XID %08x\n", ntohl(transport->tcp_xid));13471348 /* Find and lock the request corresponding to this xid */1349- spin_lock_bh(&xprt->transport_lock);1350 req = xprt_lookup_rqst(xprt, transport->tcp_xid);1351 if (!req) {1352 dprintk("RPC: XID %08x request not found!\n",1353 ntohl(transport->tcp_xid));1354- spin_unlock_bh(&xprt->transport_lock);1355 return -1;1356 }0013571358 xs_tcp_read_common(xprt, desc, req);135901360 if (!(transport->tcp_flags & TCP_RCV_COPY_DATA))1361 xprt_complete_rqst(req->rq_task, transport->tcp_copied);1362-1363- spin_unlock_bh(&xprt->transport_lock);1364 return 0;1365}1366···1382 container_of(xprt, struct sock_xprt, xprt);1383 struct rpc_rqst *req;13841385- /* Look up and lock the request corresponding to the given XID */1386- spin_lock_bh(&xprt->transport_lock);1387 req = xprt_lookup_bc_request(xprt, transport->tcp_xid);1388 if (req == NULL) {1389- spin_unlock_bh(&xprt->transport_lock);1390 printk(KERN_WARNING "Callback slot table overflowed\n");1391 xprt_force_disconnect(xprt);1392 return -1;···13951396 if (!(transport->tcp_flags & TCP_RCV_COPY_DATA))1397 xprt_complete_bc_request(req, transport->tcp_copied);1398- spin_unlock_bh(&xprt->transport_lock);13991400 return 0;1401}···1519 .arg.data = xprt,1520 };1521 unsigned long total = 0;01522 int read = 0;15231524 mutex_lock(&transport->recv_mutex);···1528 goto out;15291530 /* We use rd_desc to pass struct xprt to xs_tcp_data_recv */1531- for (;;) {1532 lock_sock(sk);1533 read = tcp_read_sock(sk, &rd_desc, xs_tcp_data_recv);1534 if (read <= 0) {1535 clear_bit(XPRT_SOCK_DATA_READY, &transport->sock_state);1536 release_sock(sk);1537- if (!test_bit(XPRT_SOCK_DATA_READY, &transport->sock_state))1538- break;1539- } else {1540- release_sock(sk);1541- total += read;1542 }001543 rd_desc.count = 65536;1544 }001545out:1546 mutex_unlock(&transport->recv_mutex);1547 trace_xs_tcp_data_ready(xprt, read, total);
···969 return;970971 /* Look up and lock the request corresponding to the given XID */972+ spin_lock(&xprt->recv_lock);973 rovr = xprt_lookup_rqst(xprt, *xp);974 if (!rovr)975 goto out_unlock;976+ xprt_pin_rqst(rovr);977+ spin_unlock(&xprt->recv_lock);978 task = rovr->rq_task;979980 copied = rovr->rq_private_buf.buflen;···981982 if (xs_local_copy_to_xdr(&rovr->rq_private_buf, skb)) {983 dprintk("RPC: sk_buff copy failed\n");984+ spin_lock(&xprt->recv_lock);985+ goto out_unpin;986 }987988+ spin_lock(&xprt->recv_lock);989 xprt_complete_rqst(task, copied);990+out_unpin:991+ xprt_unpin_rqst(rovr);992 out_unlock:993+ spin_unlock(&xprt->recv_lock);994}995996static void xs_local_data_receive(struct sock_xprt *transport)···1050 return;10511052 /* Look up and lock the request corresponding to the given XID */1053+ spin_lock(&xprt->recv_lock);1054 rovr = xprt_lookup_rqst(xprt, *xp);1055 if (!rovr)1056 goto out_unlock;1057+ xprt_pin_rqst(rovr);1058+ spin_unlock(&xprt->recv_lock);1059 task = rovr->rq_task;10601061 if ((copied = rovr->rq_private_buf.buflen) > repsize)···1062 /* Suck it into the iovec, verify checksum if not done by hw. */1063 if (csum_partial_copy_to_xdr(&rovr->rq_private_buf, skb)) {1064 __UDPX_INC_STATS(sk, UDP_MIB_INERRORS);1065+ spin_lock(&xprt->recv_lock);1066+ goto out_unpin;1067 }10681069 __UDPX_INC_STATS(sk, UDP_MIB_INDATAGRAMS);10701071+ spin_lock_bh(&xprt->transport_lock);1072 xprt_adjust_cwnd(xprt, task, copied);0001073 spin_unlock_bh(&xprt->transport_lock);1074+ spin_lock(&xprt->recv_lock);1075+ xprt_complete_rqst(task, copied);1076+out_unpin:1077+ xprt_unpin_rqst(rovr);1078+ out_unlock:1079+ spin_unlock(&xprt->recv_lock);1080}10811082static void xs_udp_data_receive(struct sock_xprt *transport)···1277 }12781279 len = desc->count;1280+ if (len > transport->tcp_reclen - transport->tcp_offset)1281+ desc->count = transport->tcp_reclen - transport->tcp_offset;1282+ r = xdr_partial_copy_from_skb(rcvbuf, transport->tcp_copied,0000000001283 desc, xdr_skb_read_bits);12841285+ if (desc->count) {00001286 /* Error when copying to the receive buffer,1287 * usually because we weren't able to allocate1288 * additional buffer pages. All we can do now···1314 transport->tcp_offset, transport->tcp_reclen);1315 return;1316 }1317+1318+ transport->tcp_copied += r;1319+ transport->tcp_offset += r;1320+ desc->count = len - r;13211322 dprintk("RPC: XID %08x read %zd bytes\n",1323 ntohl(transport->tcp_xid), r);···1343 dprintk("RPC: read reply XID %08x\n", ntohl(transport->tcp_xid));13441345 /* Find and lock the request corresponding to this xid */1346+ spin_lock(&xprt->recv_lock);1347 req = xprt_lookup_rqst(xprt, transport->tcp_xid);1348 if (!req) {1349 dprintk("RPC: XID %08x request not found!\n",1350 ntohl(transport->tcp_xid));1351+ spin_unlock(&xprt->recv_lock);1352 return -1;1353 }1354+ xprt_pin_rqst(req);1355+ spin_unlock(&xprt->recv_lock);13561357 xs_tcp_read_common(xprt, desc, req);13581359+ spin_lock(&xprt->recv_lock);1360 if (!(transport->tcp_flags & TCP_RCV_COPY_DATA))1361 xprt_complete_rqst(req->rq_task, transport->tcp_copied);1362+ xprt_unpin_rqst(req);1363+ spin_unlock(&xprt->recv_lock);1364 return 0;1365}1366···1376 container_of(xprt, struct sock_xprt, xprt);1377 struct rpc_rqst *req;13781379+ /* Look up the request corresponding to the given XID */01380 req = xprt_lookup_bc_request(xprt, transport->tcp_xid);1381 if (req == NULL) {01382 printk(KERN_WARNING "Callback slot table overflowed\n");1383 xprt_force_disconnect(xprt);1384 return -1;···13911392 if (!(transport->tcp_flags & TCP_RCV_COPY_DATA))1393 xprt_complete_bc_request(req, transport->tcp_copied);013941395 return 0;1396}···1516 .arg.data = xprt,1517 };1518 unsigned long total = 0;1519+ int loop;1520 int read = 0;15211522 mutex_lock(&transport->recv_mutex);···1524 goto out;15251526 /* We use rd_desc to pass struct xprt to xs_tcp_data_recv */1527+ for (loop = 0; loop < 64; loop++) {1528 lock_sock(sk);1529 read = tcp_read_sock(sk, &rd_desc, xs_tcp_data_recv);1530 if (read <= 0) {1531 clear_bit(XPRT_SOCK_DATA_READY, &transport->sock_state);1532 release_sock(sk);1533+ break;00001534 }1535+ release_sock(sk);1536+ total += read;1537 rd_desc.count = 65536;1538 }1539+ if (test_bit(XPRT_SOCK_DATA_READY, &transport->sock_state))1540+ queue_work(xprtiod_workqueue, &transport->recv_worker);1541out:1542 mutex_unlock(&transport->recv_mutex);1543 trace_xs_tcp_data_ready(xprt, read, total);