diff options
-rw-r--r-- | drivers/nvdimm/claim.c | 30 |
1 files changed, 26 insertions, 4 deletions
diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c index d5dc80c48b4c..8d66fbb779ed 100644 --- a/drivers/nvdimm/claim.c +++ b/drivers/nvdimm/claim.c | |||
@@ -226,6 +226,12 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns, | |||
226 | resource_size_t offset, void *buf, size_t size, int rw) | 226 | resource_size_t offset, void *buf, size_t size, int rw) |
227 | { | 227 | { |
228 | struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev); | 228 | struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev); |
229 | unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512); | ||
230 | sector_t sector = offset >> 9; | ||
231 | int rc = 0; | ||
232 | |||
233 | if (unlikely(!size)) | ||
234 | return 0; | ||
229 | 235 | ||
230 | if (unlikely(offset + size > nsio->size)) { | 236 | if (unlikely(offset + size > nsio->size)) { |
231 | dev_WARN_ONCE(&ndns->dev, 1, "request out of range\n"); | 237 | dev_WARN_ONCE(&ndns->dev, 1, "request out of range\n"); |
@@ -233,17 +239,33 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns, | |||
233 | } | 239 | } |
234 | 240 | ||
235 | if (rw == READ) { | 241 | if (rw == READ) { |
236 | unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512); | 242 | if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) |
237 | |||
238 | if (unlikely(is_bad_pmem(&nsio->bb, offset / 512, sz_align))) | ||
239 | return -EIO; | 243 | return -EIO; |
240 | return memcpy_from_pmem(buf, nsio->addr + offset, size); | 244 | return memcpy_from_pmem(buf, nsio->addr + offset, size); |
241 | } else { | 245 | } else { |
246 | |||
247 | if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) { | ||
248 | if (IS_ALIGNED(offset, 512) && IS_ALIGNED(size, 512)) { | ||
249 | long cleared; | ||
250 | |||
251 | cleared = nvdimm_clear_poison(&ndns->dev, | ||
252 | offset, size); | ||
253 | if (cleared != size) { | ||
254 | size = cleared; | ||
255 | rc = -EIO; | ||
256 | } | ||
257 | |||
258 | badblocks_clear(&nsio->bb, sector, | ||
259 | cleared >> 9); | ||
260 | } else | ||
261 | rc = -EIO; | ||
262 | } | ||
263 | |||
242 | memcpy_to_pmem(nsio->addr + offset, buf, size); | 264 | memcpy_to_pmem(nsio->addr + offset, buf, size); |
243 | nvdimm_flush(to_nd_region(ndns->dev.parent)); | 265 | nvdimm_flush(to_nd_region(ndns->dev.parent)); |
244 | } | 266 | } |
245 | 267 | ||
246 | return 0; | 268 | return rc; |
247 | } | 269 | } |
248 | 270 | ||
249 | int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio) | 271 | int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio) |