diff options
| author | Benjamin Coddington <bcodding@redhat.com> | 2018-10-18 15:01:48 -0400 |
|---|---|---|
| committer | Trond Myklebust <trond.myklebust@hammerspace.com> | 2018-10-18 17:20:57 -0400 |
| commit | fdbd1a2e4a71adcb1ae219fcfd964930d77a7f84 (patch) | |
| tree | 728f68714faa6fddc69ea60e8ff8a9f61d3ed09c | |
| parent | e732f4485a150492b286f3efc06f9b34dd6b9995 (diff) | |
nfs: Fix a missed page unlock after pg_doio()
We must check pg_error and call error_cleanup after any call to pg_doio.
Currently, we are skipping the unlock of a page if we encounter an error in
nfs_pageio_complete() before handing off the work to the RPC layer.
Signed-off-by: Benjamin Coddington <bcodding@redhat.com>
Cc: stable@vger.kernel.org
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
| -rw-r--r-- | fs/nfs/pagelist.c | 40 |
1 files changed, 21 insertions, 19 deletions
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index f97c455f5734..3b50edf6f883 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
| @@ -1110,6 +1110,20 @@ static int nfs_pageio_add_request_mirror(struct nfs_pageio_descriptor *desc, | |||
| 1110 | return ret; | 1110 | return ret; |
| 1111 | } | 1111 | } |
| 1112 | 1112 | ||
| 1113 | static void nfs_pageio_error_cleanup(struct nfs_pageio_descriptor *desc) | ||
| 1114 | { | ||
| 1115 | u32 midx; | ||
| 1116 | struct nfs_pgio_mirror *mirror; | ||
| 1117 | |||
| 1118 | if (!desc->pg_error) | ||
| 1119 | return; | ||
| 1120 | |||
| 1121 | for (midx = 0; midx < desc->pg_mirror_count; midx++) { | ||
| 1122 | mirror = &desc->pg_mirrors[midx]; | ||
| 1123 | desc->pg_completion_ops->error_cleanup(&mirror->pg_list); | ||
| 1124 | } | ||
| 1125 | } | ||
| 1126 | |||
| 1113 | int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | 1127 | int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, |
| 1114 | struct nfs_page *req) | 1128 | struct nfs_page *req) |
| 1115 | { | 1129 | { |
| @@ -1160,25 +1174,11 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | |||
| 1160 | return 1; | 1174 | return 1; |
| 1161 | 1175 | ||
| 1162 | out_failed: | 1176 | out_failed: |
| 1163 | /* | 1177 | /* remember fatal errors */ |
| 1164 | * We might have failed before sending any reqs over wire. | 1178 | if (nfs_error_is_fatal(desc->pg_error)) |
| 1165 | * Clean up rest of the reqs in mirror pg_list. | 1179 | nfs_context_set_write_error(req->wb_context, |
| 1166 | */ | 1180 | desc->pg_error); |
| 1167 | if (desc->pg_error) { | 1181 | nfs_pageio_error_cleanup(desc); |
| 1168 | struct nfs_pgio_mirror *mirror; | ||
| 1169 | void (*func)(struct list_head *); | ||
| 1170 | |||
| 1171 | /* remember fatal errors */ | ||
| 1172 | if (nfs_error_is_fatal(desc->pg_error)) | ||
| 1173 | nfs_context_set_write_error(req->wb_context, | ||
| 1174 | desc->pg_error); | ||
| 1175 | |||
| 1176 | func = desc->pg_completion_ops->error_cleanup; | ||
| 1177 | for (midx = 0; midx < desc->pg_mirror_count; midx++) { | ||
| 1178 | mirror = &desc->pg_mirrors[midx]; | ||
| 1179 | func(&mirror->pg_list); | ||
| 1180 | } | ||
| 1181 | } | ||
| 1182 | return 0; | 1182 | return 0; |
| 1183 | } | 1183 | } |
| 1184 | 1184 | ||
| @@ -1250,6 +1250,8 @@ void nfs_pageio_complete(struct nfs_pageio_descriptor *desc) | |||
| 1250 | for (midx = 0; midx < desc->pg_mirror_count; midx++) | 1250 | for (midx = 0; midx < desc->pg_mirror_count; midx++) |
| 1251 | nfs_pageio_complete_mirror(desc, midx); | 1251 | nfs_pageio_complete_mirror(desc, midx); |
| 1252 | 1252 | ||
| 1253 | if (desc->pg_error < 0) | ||
| 1254 | nfs_pageio_error_cleanup(desc); | ||
| 1253 | if (desc->pg_ops->pg_cleanup) | 1255 | if (desc->pg_ops->pg_cleanup) |
| 1254 | desc->pg_ops->pg_cleanup(desc); | 1256 | desc->pg_ops->pg_cleanup(desc); |
| 1255 | nfs_pageio_cleanup_mirroring(desc); | 1257 | nfs_pageio_cleanup_mirroring(desc); |
