Re: [PATCH v2 7/9] libnvdimm, pmem: prepare for handling badblocks via nvdimm_read_bytes()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 2016-01-06 at 14:31 -0800, Dan Williams wrote:
> When performing reads through the nvdimm_read_bytes() interface we
> still
> want to consult the badblocks list, but we do not have access to a
> gendisk in that path.  Convert the badblocks list to be a generic
> attribute of a namespace.
> 
> Signed-off-by: Dan Williams <dan.j.williams@xxxxxxxxx>
> ---
>  drivers/nvdimm/core.c |   44 +++++++++++++++++++++++++++----------
> -------
>  drivers/nvdimm/nd.h   |    4 ++--
>  drivers/nvdimm/pmem.c |   13 +++++++++----
>  3 files changed, 38 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c
> index 5541612bb449..63b7386b7299 100644
> --- a/drivers/nvdimm/core.c
> +++ b/drivers/nvdimm/core.c
> @@ -411,32 +411,41 @@ static int __add_badblock_range(struct device
> *dev, struct badblocks **bb,
>  }
>  
>  /**
> - * nvdimm_namespace_add_poison() - Convert a list of poison ranges
> to badblocks
> - * @disk:	the gendisk associated with the namespace where
> badblocks
> - *		will be stored
> + * nvdimm_namespace_badblocks() - Convert a list of poison ranges to
> badblocks
> + * @ndns:	namespace hosting potential badblocks
>   * @offset:	offset at the start of the namespace before
> 'sector 0'
> - * @ndns:	the namespace containing poison ranges
>   *
> - * The poison list generated during NFIT initialization may contain
> multiple,
> - * possibly overlapping ranges in the SPA (System Physical Address)
> space.
> - * Compare each of these ranges to the namespace currently being
> initialized,
> - * and add badblocks to the gendisk for all matching sub-ranges
> + * The poison list generated during NFIT initialization may contain
> + * multiple, possibly overlapping ranges in the SPA (System Physical
> + * Address) space.  Compare each of these ranges to the namespace
> + * currently being initialized, and add badblocks for all matching
> + * sub-ranges
>   *
>   * Return:
> - * 0 - Success
> + * valid badblocks instance on success
> + * ERR_PTR(-ENOENT) on no badblocks present
> + * ERR_PTR(-<error>) on failure
>   */
> -int nvdimm_namespace_add_poison(struct gendisk *disk,
> resource_size_t offset,
> -		struct nd_namespace_common *ndns)
> +struct badblocks *nvdimm_namespace_badblocks(struct
> nd_namespace_common *ndns,
> +		resource_size_t offset)
>  {
> -	struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns-
> >dev);
>  	struct nd_region *nd_region = to_nd_region(ndns-
> >dev.parent);
>  	struct nvdimm_bus *nvdimm_bus;
>  	struct list_head *poison_list;
>  	u64 ns_start, ns_end, ns_size;
> +	struct nd_namespace_io *nsio;
>  	struct badblocks *bb = NULL;
>  	struct nd_poison *pl;
>  	int rc;
>  
> +	/*
> +	 * For now, the addresses retrieved from an nvdimm bus are
> +	 * communicated in terms of system physical address not a
> dimm
> +	 * address (dpa).  This implies pmem only.
> +	 */
> +	if (!is_nd_pmem(&nd_region->dev))
> +		return ERR_PTR(-ENOENT);
> +	nsio = to_nd_namespace_io(&ndns->dev);
>  	ns_size = nvdimm_namespace_capacity(ndns) - offset;
>  	ns_start = nsio->res.start + offset;
>  	ns_end = nsio->res.end;
> @@ -444,7 +453,7 @@ int nvdimm_namespace_add_poison(struct gendisk
> *disk, resource_size_t offset,
>  	nvdimm_bus = to_nvdimm_bus(nd_region->dev.parent);
>  	poison_list = &nvdimm_bus->poison_list;
>  	if (list_empty(poison_list))
> -		return 0;
> +		return ERR_PTR(-ENOENT);
>  
>  	list_for_each_entry(pl, poison_list, list) {
>  		u64 pl_end = pl->start + pl->length - 1;
> @@ -467,7 +476,7 @@ int nvdimm_namespace_add_poison(struct gendisk
> *disk, resource_size_t offset,
>  			rc = __add_badblock_range(&ndns->dev, &bb,
>  					start - ns_start, len);
>  			if (rc)
> -				return rc;
> +				return ERR_PTR(rc);
>  			dev_info(&nvdimm_bus->dev,
>  				"Found a poison range (0x%llx,
> 0x%llx)\n",
>  				start, len);
> @@ -484,16 +493,17 @@ int nvdimm_namespace_add_poison(struct gendisk
> *disk, resource_size_t offset,
>  
>  			rc = __add_badblock_range(&ndns->dev, &bb,
> 0, len);
>  			if (rc)
> -				return rc;
> +				return ERR_PTR(rc);
>  			dev_info(&nvdimm_bus->dev,
>  				"Found a poison range (0x%llx,
> 0x%llx)\n",
>  				pl->start, len);
>  		}
>  	}
>  
> -	return 0;
> +	WARN_ON(!bb);

Just hit this in testing..
I think it is OK to reach this point without having a valid bb.
The poison_list has a region-wide scope, and it is possible that there
are poison locations in the region outside of the namespace currently
being set up. In this case, this namespace's bb should still be null.

> +	return bb;
>  }
> -EXPORT_SYMBOL_GPL(nvdimm_namespace_add_poison);
> +EXPORT_SYMBOL_GPL(nvdimm_namespace_badblocks);
>  
>  static int __add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64
> length)
>  {
> diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
> index 198933da83e5..65f1031f2bf9 100644
> --- a/drivers/nvdimm/nd.h
> +++ b/drivers/nvdimm/nd.h
> @@ -268,8 +268,8 @@ int nvdimm_namespace_attach_btt(struct
> nd_namespace_common *ndns);
>  int nvdimm_namespace_detach_btt(struct nd_namespace_common *ndns);
>  const char *nvdimm_namespace_disk_name(struct nd_namespace_common
> *ndns,
>  		char *name);
> -int nvdimm_namespace_add_poison(struct gendisk *disk,
> resource_size_t offset,
> -		struct nd_namespace_common *ndns);
> +struct badblocks *nvdimm_namespace_badblocks(struct
> nd_namespace_common *ndns,
> +		resource_size_t offset);
>  int nd_blk_region_init(struct nd_region *nd_region);
>  void __nd_iostat_start(struct bio *bio, unsigned long *start);
>  static inline bool nd_iostat_start(struct bio *bio, unsigned long
> *start)
> diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
> index bbe81b7fe031..eb2b1dc14335 100644
> --- a/drivers/nvdimm/pmem.c
> +++ b/drivers/nvdimm/pmem.c
> @@ -192,8 +192,8 @@ static int pmem_attach_disk(struct device *dev,
>  		struct nd_namespace_common *ndns, struct pmem_device
> *pmem)
>  {
>  	int nid = dev_to_node(dev);
> +	struct badblocks *bb;
>  	struct gendisk *disk;
> -	int ret;
>  
>  	pmem->pmem_queue = blk_alloc_queue_node(GFP_KERNEL, nid);
>  	if (!pmem->pmem_queue)
> @@ -222,10 +222,15 @@ static int pmem_attach_disk(struct device *dev,
>  	set_capacity(disk, (pmem->size - pmem->data_offset) / 512);
>  	pmem->pmem_disk = disk;
>  
> -	ret = nvdimm_namespace_add_poison(disk, pmem->data_offset,
> ndns);
> -	if (ret)
> -		return ret;
> +	bb = nvdimm_namespace_badblocks(ndns, pmem->data_offset);
> +	if (IS_ERR(bb)) {
> +		if (PTR_ERR(bb) == -ENOENT)
> +			bb = NULL;
> +		else
> +			return PTR_ERR(bb);
> +	}
>  
> +	disk->bb = bb;
>  	add_disk(disk);
>  	revalidate_disk(disk);
>  
> 
> _______________________________________________
> Linux-nvdimm mailing list
> Linux-nvdimm@xxxxxxxxxxxx
> https://lists.01.org/mailman/listinfo/linux-nvdimm
--
To unsubscribe from this list: send the line "unsubscribe linux-block" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux RAID]     [Linux SCSI]     [Linux ATA RAID]     [IDE]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Device Mapper]

  Powered by Linux