aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfsd/blocklayout.c18
1 files changed, 16 insertions, 2 deletions
diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c
index 70b8bf781fce..a0661349e7cf 100644
--- a/fs/nfsd/blocklayout.c
+++ b/fs/nfsd/blocklayout.c
@@ -216,13 +216,21 @@ static int nfsd4_scsi_identify_device(struct block_device *bdev,
216 struct request_queue *q = bdev->bd_disk->queue; 216 struct request_queue *q = bdev->bd_disk->queue;
217 struct request *rq; 217 struct request *rq;
218 struct scsi_request *req; 218 struct scsi_request *req;
219 size_t bufflen = 252, len, id_len; 219 /*
220 * The allocation length (passed in bytes 3 and 4 of the INQUIRY
221 * command descriptor block) specifies the number of bytes that have
222 * been allocated for the data-in buffer.
223 * 252 is the highest one-byte value that is a multiple of 4.
224 * 65532 is the highest two-byte value that is a multiple of 4.
225 */
226 size_t bufflen = 252, maxlen = 65532, len, id_len;
220 u8 *buf, *d, type, assoc; 227 u8 *buf, *d, type, assoc;
221 int error; 228 int retries = 1, error;
222 229
223 if (WARN_ON_ONCE(!blk_queue_scsi_passthrough(q))) 230 if (WARN_ON_ONCE(!blk_queue_scsi_passthrough(q)))
224 return -EINVAL; 231 return -EINVAL;
225 232
233again:
226 buf = kzalloc(bufflen, GFP_KERNEL); 234 buf = kzalloc(bufflen, GFP_KERNEL);
227 if (!buf) 235 if (!buf)
228 return -ENOMEM; 236 return -ENOMEM;
@@ -255,6 +263,12 @@ static int nfsd4_scsi_identify_device(struct block_device *bdev,
255 263
256 len = (buf[2] << 8) + buf[3] + 4; 264 len = (buf[2] << 8) + buf[3] + 4;
257 if (len > bufflen) { 265 if (len > bufflen) {
266 if (len <= maxlen && retries--) {
267 blk_put_request(rq);
268 kfree(buf);
269 bufflen = len;
270 goto again;
271 }
258 pr_err("pNFS: INQUIRY 0x83 response invalid (len = %zd)\n", 272 pr_err("pNFS: INQUIRY 0x83 response invalid (len = %zd)\n",
259 len); 273 len);
260 goto out_put_request; 274 goto out_put_request;