aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/nvdimm/claim.c30
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
249int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio) 271int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio)