diff mbox series

[3/7] nfsd/blocklayout: use ->get_unique_id instead of sending SCSI commands

Message ID 20211012120445.861860-4-hch@lst.de (mailing list archive)
State Superseded
Headers show
Series [1/7] block: add a ->get_unique_id method | expand

Commit Message

Christoph Hellwig Oct. 12, 2021, 12:04 p.m. UTC
Call the ->get_unique_id method to query the SCSI identifiers.  This can
use the cached VPD page in the sd driver instead of sending a command
on every LAYOUTGET.  It will also allow to support NVMe based volumes
if the draft for that ever takes off.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 fs/nfsd/Kconfig       |   1 -
 fs/nfsd/blocklayout.c | 158 +++++++++++-------------------------------
 fs/nfsd/nfs4layouts.c |   5 +-
 3 files changed, 44 insertions(+), 120 deletions(-)

Comments

J. Bruce Fields Oct. 12, 2021, 1:06 p.m. UTC | #1
On Tue, Oct 12, 2021 at 02:04:41PM +0200, Christoph Hellwig wrote:
> Call the ->get_unique_id method to query the SCSI identifiers.  This can
> use the cached VPD page in the sd driver instead of sending a command
> on every LAYOUTGET.  It will also allow to support NVMe based volumes
> if the draft for that ever takes off.


Acked-by: J. Bruce Fields <bfields@redhat.com>

(But I'm not really in a position to review scsi layout code, so this is
more just an acknowledgement that you're the expert.)

--b.

> 
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
>  fs/nfsd/Kconfig       |   1 -
>  fs/nfsd/blocklayout.c | 158 +++++++++++-------------------------------
>  fs/nfsd/nfs4layouts.c |   5 +-
>  3 files changed, 44 insertions(+), 120 deletions(-)
> 
> diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig
> index 6e9ea4ee0f737..3d1d17256a91c 100644
> --- a/fs/nfsd/Kconfig
> +++ b/fs/nfsd/Kconfig
> @@ -109,7 +109,6 @@ config NFSD_SCSILAYOUT
>  	depends on NFSD_V4 && BLOCK
>  	select NFSD_PNFS
>  	select EXPORTFS_BLOCK_OPS
> -	select SCSI_COMMON
>  	help
>  	  This option enables support for the exporting pNFS SCSI layouts
>  	  in the kernel's NFS server. The pNFS SCSI layout enables NFS
> diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c
> index c99dee99a3c15..e5c0982a381de 100644
> --- a/fs/nfsd/blocklayout.c
> +++ b/fs/nfsd/blocklayout.c
> @@ -9,9 +9,6 @@
>  #include <linux/pr.h>
>  
>  #include <linux/nfsd/debug.h>
> -#include <scsi/scsi_proto.h>
> -#include <scsi/scsi_common.h>
> -#include <scsi/scsi_request.h>
>  
>  #include "blocklayoutxdr.h"
>  #include "pnfs.h"
> @@ -211,109 +208,6 @@ const struct nfsd4_layout_ops bl_layout_ops = {
>  #endif /* CONFIG_NFSD_BLOCKLAYOUT */
>  
>  #ifdef CONFIG_NFSD_SCSILAYOUT
> -static int nfsd4_scsi_identify_device(struct block_device *bdev,
> -		struct pnfs_block_volume *b)
> -{
> -	struct request_queue *q = bdev->bd_disk->queue;
> -	struct request *rq;
> -	struct scsi_request *req;
> -	/*
> -	 * The allocation length (passed in bytes 3 and 4 of the INQUIRY
> -	 * command descriptor block) specifies the number of bytes that have
> -	 * been allocated for the data-in buffer.
> -	 * 252 is the highest one-byte value that is a multiple of 4.
> -	 * 65532 is the highest two-byte value that is a multiple of 4.
> -	 */
> -	size_t bufflen = 252, maxlen = 65532, len, id_len;
> -	u8 *buf, *d, type, assoc;
> -	int retries = 1, error;
> -
> -	if (WARN_ON_ONCE(!blk_queue_scsi_passthrough(q)))
> -		return -EINVAL;
> -
> -again:
> -	buf = kzalloc(bufflen, GFP_KERNEL);
> -	if (!buf)
> -		return -ENOMEM;
> -
> -	rq = blk_get_request(q, REQ_OP_DRV_IN, 0);
> -	if (IS_ERR(rq)) {
> -		error = -ENOMEM;
> -		goto out_free_buf;
> -	}
> -	req = scsi_req(rq);
> -
> -	error = blk_rq_map_kern(q, rq, buf, bufflen, GFP_KERNEL);
> -	if (error)
> -		goto out_put_request;
> -
> -	req->cmd[0] = INQUIRY;
> -	req->cmd[1] = 1;
> -	req->cmd[2] = 0x83;
> -	req->cmd[3] = bufflen >> 8;
> -	req->cmd[4] = bufflen & 0xff;
> -	req->cmd_len = COMMAND_SIZE(INQUIRY);
> -
> -	blk_execute_rq(NULL, rq, 1);
> -	if (req->result) {
> -		pr_err("pNFS: INQUIRY 0x83 failed with: %x\n",
> -			req->result);
> -		error = -EIO;
> -		goto out_put_request;
> -	}
> -
> -	len = (buf[2] << 8) + buf[3] + 4;
> -	if (len > bufflen) {
> -		if (len <= maxlen && retries--) {
> -			blk_put_request(rq);
> -			kfree(buf);
> -			bufflen = len;
> -			goto again;
> -		}
> -		pr_err("pNFS: INQUIRY 0x83 response invalid (len = %zd)\n",
> -			len);
> -		goto out_put_request;
> -	}
> -
> -	d = buf + 4;
> -	for (d = buf + 4; d < buf + len; d += id_len + 4) {
> -		id_len = d[3];
> -		type = d[1] & 0xf;
> -		assoc = (d[1] >> 4) & 0x3;
> -
> -		/*
> -		 * We only care about a EUI-64 and NAA designator types
> -		 * with LU association.
> -		 */
> -		if (assoc != 0x00)
> -			continue;
> -		if (type != 0x02 && type != 0x03)
> -			continue;
> -		if (id_len != 8 && id_len != 12 && id_len != 16)
> -			continue;
> -
> -		b->scsi.code_set = PS_CODE_SET_BINARY;
> -		b->scsi.designator_type = type == 0x02 ?
> -			PS_DESIGNATOR_EUI64 : PS_DESIGNATOR_NAA;
> -		b->scsi.designator_len = id_len;
> -		memcpy(b->scsi.designator, d + 4, id_len);
> -
> -		/*
> -		 * If we found a 8 or 12 byte descriptor continue on to
> -		 * see if a 16 byte one is available.  If we find a
> -		 * 16 byte descriptor we're done.
> -		 */
> -		if (id_len == 16)
> -			break;
> -	}
> -
> -out_put_request:
> -	blk_put_request(rq);
> -out_free_buf:
> -	kfree(buf);
> -	return error;
> -}
> -
>  #define NFSD_MDS_PR_KEY		0x0100000000000000ULL
>  
>  /*
> @@ -325,6 +219,31 @@ static u64 nfsd4_scsi_pr_key(struct nfs4_client *clp)
>  	return ((u64)clp->cl_clientid.cl_boot << 32) | clp->cl_clientid.cl_id;
>  }
>  
> +static const u8 designator_types[] = {
> +	PS_DESIGNATOR_EUI64,
> +	PS_DESIGNATOR_NAA,
> +};
> +
> +static int
> +nfsd4_block_get_unique_id(struct gendisk *disk, struct pnfs_block_volume *b)
> +{
> +	int ret, i;
> +
> +	for (i = 0; i < ARRAY_SIZE(designator_types); i++) {
> +		u8 type = designator_types[i];
> +
> +		ret = disk->fops->get_unique_id(disk, b->scsi.designator, type);
> +		if (ret > 0) {
> +			b->scsi.code_set = PS_CODE_SET_BINARY;
> +			b->scsi.designator_type = type;
> +			b->scsi.designator_len = ret;
> +			return 0;
> +		}
> +	}
> +
> +	return -EINVAL;
> +}
> +
>  static int
>  nfsd4_block_get_device_info_scsi(struct super_block *sb,
>  		struct nfs4_client *clp,
> @@ -333,7 +252,7 @@ nfsd4_block_get_device_info_scsi(struct super_block *sb,
>  	struct pnfs_block_deviceaddr *dev;
>  	struct pnfs_block_volume *b;
>  	const struct pr_ops *ops;
> -	int error;
> +	int ret;
>  
>  	dev = kzalloc(sizeof(struct pnfs_block_deviceaddr) +
>  		      sizeof(struct pnfs_block_volume), GFP_KERNEL);
> @@ -347,33 +266,38 @@ nfsd4_block_get_device_info_scsi(struct super_block *sb,
>  	b->type = PNFS_BLOCK_VOLUME_SCSI;
>  	b->scsi.pr_key = nfsd4_scsi_pr_key(clp);
>  
> -	error = nfsd4_scsi_identify_device(sb->s_bdev, b);
> -	if (error)
> -		return error;
> +	ret = nfsd4_block_get_unique_id(sb->s_bdev->bd_disk, b);
> +	if (ret < 0)
> +		goto out_free_dev;
>  
> +	ret = -EINVAL;
>  	ops = sb->s_bdev->bd_disk->fops->pr_ops;
>  	if (!ops) {
>  		pr_err("pNFS: device %s does not support PRs.\n",
>  			sb->s_id);
> -		return -EINVAL;
> +		goto out_free_dev;
>  	}
>  
> -	error = ops->pr_register(sb->s_bdev, 0, NFSD_MDS_PR_KEY, true);
> -	if (error) {
> +	ret = ops->pr_register(sb->s_bdev, 0, NFSD_MDS_PR_KEY, true);
> +	if (ret) {
>  		pr_err("pNFS: failed to register key for device %s.\n",
>  			sb->s_id);
> -		return -EINVAL;
> +		goto out_free_dev;
>  	}
>  
> -	error = ops->pr_reserve(sb->s_bdev, NFSD_MDS_PR_KEY,
> +	ret = ops->pr_reserve(sb->s_bdev, NFSD_MDS_PR_KEY,
>  			PR_EXCLUSIVE_ACCESS_REG_ONLY, 0);
> -	if (error) {
> +	if (ret) {
>  		pr_err("pNFS: failed to reserve device %s.\n",
>  			sb->s_id);
> -		return -EINVAL;
> +		goto out_free_dev;
>  	}
>  
>  	return 0;
> +
> +out_free_dev:
> +	kfree(dev);
> +	return ret;
>  }
>  
>  static __be32
> diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c
> index a97873f2d22b0..6d1b5bb051c56 100644
> --- a/fs/nfsd/nfs4layouts.c
> +++ b/fs/nfsd/nfs4layouts.c
> @@ -145,8 +145,9 @@ void nfsd4_setup_layout_type(struct svc_export *exp)
>  #ifdef CONFIG_NFSD_SCSILAYOUT
>  	if (sb->s_export_op->map_blocks &&
>  	    sb->s_export_op->commit_blocks &&
> -	    sb->s_bdev && sb->s_bdev->bd_disk->fops->pr_ops &&
> -		blk_queue_scsi_passthrough(sb->s_bdev->bd_disk->queue))
> +	    sb->s_bdev &&
> +	    sb->s_bdev->bd_disk->fops->pr_ops &&
> +	    sb->s_bdev->bd_disk->fops->get_unique_id)
>  		exp->ex_layout_types |= 1 << LAYOUT_SCSI;
>  #endif
>  }
> -- 
> 2.30.2
Hannes Reinecke Oct. 14, 2021, 7:32 a.m. UTC | #2
On 10/12/21 2:04 PM, Christoph Hellwig wrote:
> Call the ->get_unique_id method to query the SCSI identifiers.  This can
> use the cached VPD page in the sd driver instead of sending a command
> on every LAYOUTGET.  It will also allow to support NVMe based volumes
> if the draft for that ever takes off.
> 
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
>   fs/nfsd/Kconfig       |   1 -
>   fs/nfsd/blocklayout.c | 158 +++++++++++-------------------------------
>   fs/nfsd/nfs4layouts.c |   5 +-
>   3 files changed, 44 insertions(+), 120 deletions(-)
> 
Not that I'm an NFS expert, but anyway:

Reviewed-by: Hannes Reinecke <hare@suse.de>

Cheers,

Hannes
diff mbox series

Patch

diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig
index 6e9ea4ee0f737..3d1d17256a91c 100644
--- a/fs/nfsd/Kconfig
+++ b/fs/nfsd/Kconfig
@@ -109,7 +109,6 @@  config NFSD_SCSILAYOUT
 	depends on NFSD_V4 && BLOCK
 	select NFSD_PNFS
 	select EXPORTFS_BLOCK_OPS
-	select SCSI_COMMON
 	help
 	  This option enables support for the exporting pNFS SCSI layouts
 	  in the kernel's NFS server. The pNFS SCSI layout enables NFS
diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c
index c99dee99a3c15..e5c0982a381de 100644
--- a/fs/nfsd/blocklayout.c
+++ b/fs/nfsd/blocklayout.c
@@ -9,9 +9,6 @@ 
 #include <linux/pr.h>
 
 #include <linux/nfsd/debug.h>
-#include <scsi/scsi_proto.h>
-#include <scsi/scsi_common.h>
-#include <scsi/scsi_request.h>
 
 #include "blocklayoutxdr.h"
 #include "pnfs.h"
@@ -211,109 +208,6 @@  const struct nfsd4_layout_ops bl_layout_ops = {
 #endif /* CONFIG_NFSD_BLOCKLAYOUT */
 
 #ifdef CONFIG_NFSD_SCSILAYOUT
-static int nfsd4_scsi_identify_device(struct block_device *bdev,
-		struct pnfs_block_volume *b)
-{
-	struct request_queue *q = bdev->bd_disk->queue;
-	struct request *rq;
-	struct scsi_request *req;
-	/*
-	 * The allocation length (passed in bytes 3 and 4 of the INQUIRY
-	 * command descriptor block) specifies the number of bytes that have
-	 * been allocated for the data-in buffer.
-	 * 252 is the highest one-byte value that is a multiple of 4.
-	 * 65532 is the highest two-byte value that is a multiple of 4.
-	 */
-	size_t bufflen = 252, maxlen = 65532, len, id_len;
-	u8 *buf, *d, type, assoc;
-	int retries = 1, error;
-
-	if (WARN_ON_ONCE(!blk_queue_scsi_passthrough(q)))
-		return -EINVAL;
-
-again:
-	buf = kzalloc(bufflen, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	rq = blk_get_request(q, REQ_OP_DRV_IN, 0);
-	if (IS_ERR(rq)) {
-		error = -ENOMEM;
-		goto out_free_buf;
-	}
-	req = scsi_req(rq);
-
-	error = blk_rq_map_kern(q, rq, buf, bufflen, GFP_KERNEL);
-	if (error)
-		goto out_put_request;
-
-	req->cmd[0] = INQUIRY;
-	req->cmd[1] = 1;
-	req->cmd[2] = 0x83;
-	req->cmd[3] = bufflen >> 8;
-	req->cmd[4] = bufflen & 0xff;
-	req->cmd_len = COMMAND_SIZE(INQUIRY);
-
-	blk_execute_rq(NULL, rq, 1);
-	if (req->result) {
-		pr_err("pNFS: INQUIRY 0x83 failed with: %x\n",
-			req->result);
-		error = -EIO;
-		goto out_put_request;
-	}
-
-	len = (buf[2] << 8) + buf[3] + 4;
-	if (len > bufflen) {
-		if (len <= maxlen && retries--) {
-			blk_put_request(rq);
-			kfree(buf);
-			bufflen = len;
-			goto again;
-		}
-		pr_err("pNFS: INQUIRY 0x83 response invalid (len = %zd)\n",
-			len);
-		goto out_put_request;
-	}
-
-	d = buf + 4;
-	for (d = buf + 4; d < buf + len; d += id_len + 4) {
-		id_len = d[3];
-		type = d[1] & 0xf;
-		assoc = (d[1] >> 4) & 0x3;
-
-		/*
-		 * We only care about a EUI-64 and NAA designator types
-		 * with LU association.
-		 */
-		if (assoc != 0x00)
-			continue;
-		if (type != 0x02 && type != 0x03)
-			continue;
-		if (id_len != 8 && id_len != 12 && id_len != 16)
-			continue;
-
-		b->scsi.code_set = PS_CODE_SET_BINARY;
-		b->scsi.designator_type = type == 0x02 ?
-			PS_DESIGNATOR_EUI64 : PS_DESIGNATOR_NAA;
-		b->scsi.designator_len = id_len;
-		memcpy(b->scsi.designator, d + 4, id_len);
-
-		/*
-		 * If we found a 8 or 12 byte descriptor continue on to
-		 * see if a 16 byte one is available.  If we find a
-		 * 16 byte descriptor we're done.
-		 */
-		if (id_len == 16)
-			break;
-	}
-
-out_put_request:
-	blk_put_request(rq);
-out_free_buf:
-	kfree(buf);
-	return error;
-}
-
 #define NFSD_MDS_PR_KEY		0x0100000000000000ULL
 
 /*
@@ -325,6 +219,31 @@  static u64 nfsd4_scsi_pr_key(struct nfs4_client *clp)
 	return ((u64)clp->cl_clientid.cl_boot << 32) | clp->cl_clientid.cl_id;
 }
 
+static const u8 designator_types[] = {
+	PS_DESIGNATOR_EUI64,
+	PS_DESIGNATOR_NAA,
+};
+
+static int
+nfsd4_block_get_unique_id(struct gendisk *disk, struct pnfs_block_volume *b)
+{
+	int ret, i;
+
+	for (i = 0; i < ARRAY_SIZE(designator_types); i++) {
+		u8 type = designator_types[i];
+
+		ret = disk->fops->get_unique_id(disk, b->scsi.designator, type);
+		if (ret > 0) {
+			b->scsi.code_set = PS_CODE_SET_BINARY;
+			b->scsi.designator_type = type;
+			b->scsi.designator_len = ret;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
 static int
 nfsd4_block_get_device_info_scsi(struct super_block *sb,
 		struct nfs4_client *clp,
@@ -333,7 +252,7 @@  nfsd4_block_get_device_info_scsi(struct super_block *sb,
 	struct pnfs_block_deviceaddr *dev;
 	struct pnfs_block_volume *b;
 	const struct pr_ops *ops;
-	int error;
+	int ret;
 
 	dev = kzalloc(sizeof(struct pnfs_block_deviceaddr) +
 		      sizeof(struct pnfs_block_volume), GFP_KERNEL);
@@ -347,33 +266,38 @@  nfsd4_block_get_device_info_scsi(struct super_block *sb,
 	b->type = PNFS_BLOCK_VOLUME_SCSI;
 	b->scsi.pr_key = nfsd4_scsi_pr_key(clp);
 
-	error = nfsd4_scsi_identify_device(sb->s_bdev, b);
-	if (error)
-		return error;
+	ret = nfsd4_block_get_unique_id(sb->s_bdev->bd_disk, b);
+	if (ret < 0)
+		goto out_free_dev;
 
+	ret = -EINVAL;
 	ops = sb->s_bdev->bd_disk->fops->pr_ops;
 	if (!ops) {
 		pr_err("pNFS: device %s does not support PRs.\n",
 			sb->s_id);
-		return -EINVAL;
+		goto out_free_dev;
 	}
 
-	error = ops->pr_register(sb->s_bdev, 0, NFSD_MDS_PR_KEY, true);
-	if (error) {
+	ret = ops->pr_register(sb->s_bdev, 0, NFSD_MDS_PR_KEY, true);
+	if (ret) {
 		pr_err("pNFS: failed to register key for device %s.\n",
 			sb->s_id);
-		return -EINVAL;
+		goto out_free_dev;
 	}
 
-	error = ops->pr_reserve(sb->s_bdev, NFSD_MDS_PR_KEY,
+	ret = ops->pr_reserve(sb->s_bdev, NFSD_MDS_PR_KEY,
 			PR_EXCLUSIVE_ACCESS_REG_ONLY, 0);
-	if (error) {
+	if (ret) {
 		pr_err("pNFS: failed to reserve device %s.\n",
 			sb->s_id);
-		return -EINVAL;
+		goto out_free_dev;
 	}
 
 	return 0;
+
+out_free_dev:
+	kfree(dev);
+	return ret;
 }
 
 static __be32
diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c
index a97873f2d22b0..6d1b5bb051c56 100644
--- a/fs/nfsd/nfs4layouts.c
+++ b/fs/nfsd/nfs4layouts.c
@@ -145,8 +145,9 @@  void nfsd4_setup_layout_type(struct svc_export *exp)
 #ifdef CONFIG_NFSD_SCSILAYOUT
 	if (sb->s_export_op->map_blocks &&
 	    sb->s_export_op->commit_blocks &&
-	    sb->s_bdev && sb->s_bdev->bd_disk->fops->pr_ops &&
-		blk_queue_scsi_passthrough(sb->s_bdev->bd_disk->queue))
+	    sb->s_bdev &&
+	    sb->s_bdev->bd_disk->fops->pr_ops &&
+	    sb->s_bdev->bd_disk->fops->get_unique_id)
 		exp->ex_layout_types |= 1 << LAYOUT_SCSI;
 #endif
 }