[PATCH 06/21] usb/gadget: f_mass_storage: add a level of indirection for luns storage

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

 



This is needed to prepare for configfs integration.

So far the luns have been allocated during gadget's initialization, based
on the nluns module parameter's value; the exact number is known when the
gadget is initialized and that number of luns is allocated in one go; they
all will be used.

When configfs is in place, the luns will be created one-by-one by the user.
Once the user is satisfied with the number of luns, they activate the
gadget. The number of luns must be <= FSG_MAX_LUN (currently 8), but other
than that it is not known up front and the user need not use contiguous
numbering (apart from the default lun #0). On the other hand, the function
code uses lun numbers to identify them and the number needs to be used
as an index into an array.

Given the above, an array needs to be allocated, but it might happen that
7 out of its 8 elements will not be used. On my machine
sizeof(struct fsg_lun) == 462, so > 3k of memory is allocated but not used
in the worst case.

By adding another level of indirection (allocating an array of pointers
to struct fsg_lun and then allocating individual luns instead of an array
of struct fsg_luns) at most 7 pointers are wasted, which is much less.

This patch also changes some for/while loops to cope with the fact
that in the luns array some entries are potentially empty.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@xxxxxxxxxxx>
Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx>
---
 drivers/usb/gadget/f_mass_storage.c |  421 ++++++++++++++++++-----------------
 1 files changed, 219 insertions(+), 202 deletions(-)

diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index c36e208..a7e9269 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -274,8 +274,8 @@ struct fsg_common {
 
 	unsigned int		nluns;
 	unsigned int		lun;
-	struct fsg_lun		*luns;
-	struct fsg_lun		*curlun;
+	struct fsg_lun		**luns;
+	struct fsg_lun		**curlun;
 
 	unsigned int		bulk_out_maxpacket;
 	enum fsg_state		state;		/* For exception handling */
@@ -621,7 +621,7 @@ static int sleep_thread(struct fsg_common *common)
 
 static int do_read(struct fsg_common *common)
 {
-	struct fsg_lun		*curlun = common->curlun;
+	struct fsg_lun		**curlun = common->curlun;
 	u32			lba;
 	struct fsg_buffhd	*bh;
 	int			rc;
@@ -645,15 +645,15 @@ static int do_read(struct fsg_common *common)
 		 * cache), but we don't implement them.
 		 */
 		if ((common->cmnd[1] & ~0x18) != 0) {
-			curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+			(*curlun)->sense_data = SS_INVALID_FIELD_IN_CDB;
 			return -EINVAL;
 		}
 	}
-	if (lba >= curlun->num_sectors) {
-		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+	if (lba >= (*curlun)->num_sectors) {
+		(*curlun)->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
 		return -EINVAL;
 	}
-	file_offset = ((loff_t) lba) << curlun->blkbits;
+	file_offset = ((loff_t) lba) << (*curlun)->blkbits;
 
 	/* Carry out the file reads */
 	amount_left = common->data_size_from_cmnd;
@@ -669,7 +669,7 @@ static int do_read(struct fsg_common *common)
 		 */
 		amount = min(amount_left, FSG_BUFLEN);
 		amount = min((loff_t)amount,
-			     curlun->file_length - file_offset);
+			     (*curlun)->file_length - file_offset);
 
 		/* Wait for the next buffer to become available */
 		bh = common->next_buffhd_to_fill;
@@ -684,11 +684,11 @@ static int do_read(struct fsg_common *common)
 		 * end with an empty buffer.
 		 */
 		if (amount == 0) {
-			curlun->sense_data =
+			(*curlun)->sense_data =
 					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-			curlun->sense_data_info =
-					file_offset >> curlun->blkbits;
-			curlun->info_valid = 1;
+			(*curlun)->sense_data_info =
+					file_offset >> (*curlun)->blkbits;
+			(*curlun)->info_valid = 1;
 			bh->inreq->length = 0;
 			bh->state = BUF_STATE_FULL;
 			break;
@@ -696,21 +696,21 @@ static int do_read(struct fsg_common *common)
 
 		/* Perform the read */
 		file_offset_tmp = file_offset;
-		nread = vfs_read(curlun->filp,
+		nread = vfs_read((*curlun)->filp,
 				 (char __user *)bh->buf,
 				 amount, &file_offset_tmp);
-		VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
+		VLDBG(*curlun, "file read %u @ %llu -> %d\n", amount,
 		      (unsigned long long)file_offset, (int)nread);
 		if (signal_pending(current))
 			return -EINTR;
 
 		if (nread < 0) {
-			LDBG(curlun, "error in file read: %d\n", (int)nread);
+			LDBG(*curlun, "error in file read: %d\n", (int)nread);
 			nread = 0;
 		} else if (nread < amount) {
-			LDBG(curlun, "partial file read: %d/%u\n",
+			LDBG(*curlun, "partial file read: %d/%u\n",
 			     (int)nread, amount);
-			nread = round_down(nread, curlun->blksize);
+			nread = round_down(nread, (*curlun)->blksize);
 		}
 		file_offset  += nread;
 		amount_left  -= nread;
@@ -726,10 +726,10 @@ static int do_read(struct fsg_common *common)
 
 		/* If an error occurred, report it and its position */
 		if (nread < amount) {
-			curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
-			curlun->sense_data_info =
-					file_offset >> curlun->blkbits;
-			curlun->info_valid = 1;
+			(*curlun)->sense_data = SS_UNRECOVERED_READ_ERROR;
+			(*curlun)->sense_data_info =
+					file_offset >> (*curlun)->blkbits;
+			(*curlun)->info_valid = 1;
 			break;
 		}
 
@@ -752,7 +752,7 @@ static int do_read(struct fsg_common *common)
 
 static int do_write(struct fsg_common *common)
 {
-	struct fsg_lun		*curlun = common->curlun;
+	struct fsg_lun		**curlun = common->curlun;
 	u32			lba;
 	struct fsg_buffhd	*bh;
 	int			get_some_more;
@@ -762,13 +762,13 @@ static int do_write(struct fsg_common *common)
 	ssize_t			nwritten;
 	int			rc;
 
-	if (curlun->ro) {
-		curlun->sense_data = SS_WRITE_PROTECTED;
+	if ((*curlun)->ro) {
+		(*curlun)->sense_data = SS_WRITE_PROTECTED;
 		return -EINVAL;
 	}
-	spin_lock(&curlun->filp->f_lock);
-	curlun->filp->f_flags &= ~O_SYNC;	/* Default is not to wait */
-	spin_unlock(&curlun->filp->f_lock);
+	spin_lock(&(*curlun)->filp->f_lock);
+	(*curlun)->filp->f_flags &= ~O_SYNC;	/* Default is not to wait */
+	spin_unlock(&(*curlun)->filp->f_lock);
 
 	/*
 	 * Get the starting Logical Block Address and check that it's
@@ -786,23 +786,23 @@ static int do_write(struct fsg_common *common)
 		 * performing synchronous output.
 		 */
 		if (common->cmnd[1] & ~0x18) {
-			curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+			(*curlun)->sense_data = SS_INVALID_FIELD_IN_CDB;
 			return -EINVAL;
 		}
-		if (!curlun->nofua && (common->cmnd[1] & 0x08)) { /* FUA */
-			spin_lock(&curlun->filp->f_lock);
-			curlun->filp->f_flags |= O_SYNC;
-			spin_unlock(&curlun->filp->f_lock);
+		if (!(*curlun)->nofua && (common->cmnd[1] & 0x08)) { /* FUA */
+			spin_lock(&(*curlun)->filp->f_lock);
+			(*curlun)->filp->f_flags |= O_SYNC;
+			spin_unlock(&(*curlun)->filp->f_lock);
 		}
 	}
-	if (lba >= curlun->num_sectors) {
-		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+	if (lba >= (*curlun)->num_sectors) {
+		(*curlun)->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
 		return -EINVAL;
 	}
 
 	/* Carry out the file writes */
 	get_some_more = 1;
-	file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
+	file_offset = usb_offset = ((loff_t) lba) << (*curlun)->blkbits;
 	amount_left_to_req = common->data_size_from_cmnd;
 	amount_left_to_write = common->data_size_from_cmnd;
 
@@ -820,13 +820,13 @@ static int do_write(struct fsg_common *common)
 			amount = min(amount_left_to_req, FSG_BUFLEN);
 
 			/* Beyond the end of the backing file? */
-			if (usb_offset >= curlun->file_length) {
+			if (usb_offset >= (*curlun)->file_length) {
 				get_some_more = 0;
-				curlun->sense_data =
+				(*curlun)->sense_data =
 					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-				curlun->sense_data_info =
-					usb_offset >> curlun->blkbits;
-				curlun->info_valid = 1;
+				(*curlun)->sense_data_info =
+					usb_offset >> (*curlun)->blkbits;
+				(*curlun)->info_valid = 1;
 				continue;
 			}
 
@@ -861,20 +861,22 @@ static int do_write(struct fsg_common *common)
 
 			/* Did something go wrong with the transfer? */
 			if (bh->outreq->status != 0) {
-				curlun->sense_data = SS_COMMUNICATION_FAILURE;
-				curlun->sense_data_info =
-					file_offset >> curlun->blkbits;
-				curlun->info_valid = 1;
+				(*curlun)->sense_data =
+					SS_COMMUNICATION_FAILURE;
+				(*curlun)->sense_data_info =
+					file_offset >> (*curlun)->blkbits;
+				(*curlun)->info_valid = 1;
 				break;
 			}
 
 			amount = bh->outreq->actual;
-			if (curlun->file_length - file_offset < amount) {
-				LERROR(curlun,
+			if ((*curlun)->file_length - file_offset < amount) {
+				LERROR(*curlun,
 				       "write %u @ %llu beyond end %llu\n",
 				       amount, (unsigned long long)file_offset,
-				       (unsigned long long)curlun->file_length);
-				amount = curlun->file_length - file_offset;
+				       (unsigned long long)
+							(*curlun)->file_length);
+				amount = (*curlun)->file_length - file_offset;
 			}
 
 			/* Don't accept excess data.  The spec doesn't say
@@ -883,28 +885,29 @@ static int do_write(struct fsg_common *common)
 			amount = min(amount, bh->bulk_out_intended_length);
 
 			/* Don't write a partial block */
-			amount = round_down(amount, curlun->blksize);
+			amount = round_down(amount, (*curlun)->blksize);
 			if (amount == 0)
 				goto empty_write;
 
 			/* Perform the write */
 			file_offset_tmp = file_offset;
-			nwritten = vfs_write(curlun->filp,
+			nwritten = vfs_write((*curlun)->filp,
 					     (char __user *)bh->buf,
 					     amount, &file_offset_tmp);
-			VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,
+			VLDBG(*curlun, "file write %u @ %llu -> %d\n", amount,
 			      (unsigned long long)file_offset, (int)nwritten);
 			if (signal_pending(current))
 				return -EINTR;		/* Interrupted! */
 
 			if (nwritten < 0) {
-				LDBG(curlun, "error in file write: %d\n",
+				LDBG(*curlun, "error in file write: %d\n",
 				     (int)nwritten);
 				nwritten = 0;
 			} else if (nwritten < amount) {
-				LDBG(curlun, "partial file write: %d/%u\n",
+				LDBG(*curlun, "partial file write: %d/%u\n",
 				     (int)nwritten, amount);
-				nwritten = round_down(nwritten, curlun->blksize);
+				nwritten = round_down(nwritten,
+						      (*curlun)->blksize);
 			}
 			file_offset += nwritten;
 			amount_left_to_write -= nwritten;
@@ -912,10 +915,10 @@ static int do_write(struct fsg_common *common)
 
 			/* If an error occurred, report it and its position */
 			if (nwritten < amount) {
-				curlun->sense_data = SS_WRITE_ERROR;
-				curlun->sense_data_info =
-					file_offset >> curlun->blkbits;
-				curlun->info_valid = 1;
+				(*curlun)->sense_data = SS_WRITE_ERROR;
+				(*curlun)->sense_data_info =
+					file_offset >> (*curlun)->blkbits;
+				(*curlun)->info_valid = 1;
 				break;
 			}
 
@@ -942,14 +945,14 @@ static int do_write(struct fsg_common *common)
 
 static int do_synchronize_cache(struct fsg_common *common)
 {
-	struct fsg_lun	*curlun = common->curlun;
+	struct fsg_lun	**curlun = common->curlun;
 	int		rc;
 
 	/* We ignore the requested LBA and write out all file's
 	 * dirty data buffers. */
-	rc = fsg_lun_fsync_sub(curlun);
+	rc = fsg_lun_fsync_sub(*curlun);
 	if (rc)
-		curlun->sense_data = SS_WRITE_ERROR;
+		(*curlun)->sense_data = SS_WRITE_ERROR;
 	return 0;
 }
 
@@ -968,7 +971,7 @@ static void invalidate_sub(struct fsg_lun *curlun)
 
 static int do_verify(struct fsg_common *common)
 {
-	struct fsg_lun		*curlun = common->curlun;
+	struct fsg_lun		**curlun = common->curlun;
 	u32			lba;
 	u32			verification_length;
 	struct fsg_buffhd	*bh = common->next_buffhd_to_fill;
@@ -982,8 +985,8 @@ static int do_verify(struct fsg_common *common)
 	 * not too big.
 	 */
 	lba = get_unaligned_be32(&common->cmnd[2]);
-	if (lba >= curlun->num_sectors) {
-		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+	if (lba >= (*curlun)->num_sectors) {
+		(*curlun)->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
 		return -EINVAL;
 	}
 
@@ -992,7 +995,7 @@ static int do_verify(struct fsg_common *common)
 	 * cache) but we don't implement it.
 	 */
 	if (common->cmnd[1] & ~0x10) {
-		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		(*curlun)->sense_data = SS_INVALID_FIELD_IN_CDB;
 		return -EINVAL;
 	}
 
@@ -1001,15 +1004,15 @@ static int do_verify(struct fsg_common *common)
 		return -EIO;		/* No default reply */
 
 	/* Prepare to carry out the file verify */
-	amount_left = verification_length << curlun->blkbits;
-	file_offset = ((loff_t) lba) << curlun->blkbits;
+	amount_left = verification_length << (*curlun)->blkbits;
+	file_offset = ((loff_t) lba) << (*curlun)->blkbits;
 
 	/* Write out all the dirty buffers before invalidating them */
-	fsg_lun_fsync_sub(curlun);
+	fsg_lun_fsync_sub((*curlun));
 	if (signal_pending(current))
 		return -EINTR;
 
-	invalidate_sub(curlun);
+	invalidate_sub((*curlun));
 	if (signal_pending(current))
 		return -EINTR;
 
@@ -1023,40 +1026,40 @@ static int do_verify(struct fsg_common *common)
 		 */
 		amount = min(amount_left, FSG_BUFLEN);
 		amount = min((loff_t)amount,
-			     curlun->file_length - file_offset);
+			     (*curlun)->file_length - file_offset);
 		if (amount == 0) {
-			curlun->sense_data =
+			(*curlun)->sense_data =
 					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-			curlun->sense_data_info =
-				file_offset >> curlun->blkbits;
-			curlun->info_valid = 1;
+			(*curlun)->sense_data_info =
+				file_offset >> (*curlun)->blkbits;
+			(*curlun)->info_valid = 1;
 			break;
 		}
 
 		/* Perform the read */
 		file_offset_tmp = file_offset;
-		nread = vfs_read(curlun->filp,
+		nread = vfs_read((*curlun)->filp,
 				(char __user *) bh->buf,
 				amount, &file_offset_tmp);
-		VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
+		VLDBG(*curlun, "file read %u @ %llu -> %d\n", amount,
 				(unsigned long long) file_offset,
 				(int) nread);
 		if (signal_pending(current))
 			return -EINTR;
 
 		if (nread < 0) {
-			LDBG(curlun, "error in file verify: %d\n", (int)nread);
+			LDBG(*curlun, "error in file verify: %d\n", (int)nread);
 			nread = 0;
 		} else if (nread < amount) {
-			LDBG(curlun, "partial file verify: %d/%u\n",
+			LDBG(*curlun, "partial file verify: %d/%u\n",
 			     (int)nread, amount);
-			nread = round_down(nread, curlun->blksize);
+			nread = round_down(nread, (*curlun)->blksize);
 		}
 		if (nread == 0) {
-			curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
-			curlun->sense_data_info =
-				file_offset >> curlun->blkbits;
-			curlun->info_valid = 1;
+			(*curlun)->sense_data = SS_UNRECOVERED_READ_ERROR;
+			(*curlun)->sense_data_info =
+				file_offset >> (*curlun)->blkbits;
+			(*curlun)->info_valid = 1;
 			break;
 		}
 		file_offset += nread;
@@ -1070,10 +1073,10 @@ static int do_verify(struct fsg_common *common)
 
 static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh)
 {
-	struct fsg_lun *curlun = common->curlun;
+	struct fsg_lun **curlun = common->curlun;
 	u8	*buf = (u8 *) bh->buf;
 
-	if (!curlun) {		/* Unsupported LUNs are okay */
+	if (!*curlun) {		/* Unsupported LUNs are okay */
 		common->bad_lun_okay = 1;
 		memset(buf, 0, 36);
 		buf[0] = 0x7f;		/* Unsupported, no device-type */
@@ -1081,8 +1084,8 @@ static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh)
 		return 36;
 	}
 
-	buf[0] = curlun->cdrom ? TYPE_ROM : TYPE_DISK;
-	buf[1] = curlun->removable ? 0x80 : 0;
+	buf[0] = (*curlun)->cdrom ? TYPE_ROM : TYPE_DISK;
+	buf[1] = (*curlun)->removable ? 0x80 : 0;
 	buf[2] = 2;		/* ANSI SCSI level 2 */
 	buf[3] = 2;		/* SCSI-2 INQUIRY data format */
 	buf[4] = 31;		/* Additional length */
@@ -1095,7 +1098,7 @@ static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh)
 
 static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh)
 {
-	struct fsg_lun	*curlun = common->curlun;
+	struct fsg_lun	**curlun = common->curlun;
 	u8		*buf = (u8 *) bh->buf;
 	u32		sd, sdinfo;
 	int		valid;
@@ -1116,24 +1119,24 @@ static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh)
 	 * FSG normally uses option a); enable this code to use option b).
 	 */
 #if 0
-	if (curlun && curlun->unit_attention_data != SS_NO_SENSE) {
-		curlun->sense_data = curlun->unit_attention_data;
-		curlun->unit_attention_data = SS_NO_SENSE;
+	if (*curlun && (*curlun)->unit_attention_data != SS_NO_SENSE) {
+		(*curlun)->sense_data = (*curlun)->unit_attention_data;
+		(*curlun)->unit_attention_data = SS_NO_SENSE;
 	}
 #endif
 
-	if (!curlun) {		/* Unsupported LUNs are okay */
+	if (!*curlun) {		/* Unsupported LUNs are okay */
 		common->bad_lun_okay = 1;
 		sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
 		sdinfo = 0;
 		valid = 0;
 	} else {
-		sd = curlun->sense_data;
-		sdinfo = curlun->sense_data_info;
-		valid = curlun->info_valid << 7;
-		curlun->sense_data = SS_NO_SENSE;
-		curlun->sense_data_info = 0;
-		curlun->info_valid = 0;
+		sd = (*curlun)->sense_data;
+		sdinfo = (*curlun)->sense_data_info;
+		valid = (*curlun)->info_valid << 7;
+		(*curlun)->sense_data = SS_NO_SENSE;
+		(*curlun)->sense_data_info = 0;
+		(*curlun)->info_valid = 0;
 	}
 
 	memset(buf, 0, 18);
@@ -1148,36 +1151,36 @@ static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh)
 
 static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh)
 {
-	struct fsg_lun	*curlun = common->curlun;
+	struct fsg_lun	**curlun = common->curlun;
 	u32		lba = get_unaligned_be32(&common->cmnd[2]);
 	int		pmi = common->cmnd[8];
 	u8		*buf = (u8 *)bh->buf;
 
 	/* Check the PMI and LBA fields */
 	if (pmi > 1 || (pmi == 0 && lba != 0)) {
-		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		(*curlun)->sense_data = SS_INVALID_FIELD_IN_CDB;
 		return -EINVAL;
 	}
 
-	put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
+	put_unaligned_be32((*curlun)->num_sectors - 1, &buf[0]);
 						/* Max logical block */
-	put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */
+	put_unaligned_be32((*curlun)->blksize, &buf[4]);/* Block length */
 	return 8;
 }
 
 static int do_read_header(struct fsg_common *common, struct fsg_buffhd *bh)
 {
-	struct fsg_lun	*curlun = common->curlun;
+	struct fsg_lun	**curlun = common->curlun;
 	int		msf = common->cmnd[1] & 0x02;
 	u32		lba = get_unaligned_be32(&common->cmnd[2]);
 	u8		*buf = (u8 *)bh->buf;
 
 	if (common->cmnd[1] & ~0x02) {		/* Mask away MSF */
-		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		(*curlun)->sense_data = SS_INVALID_FIELD_IN_CDB;
 		return -EINVAL;
 	}
-	if (lba >= curlun->num_sectors) {
-		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+	if (lba >= (*curlun)->num_sectors) {
+		(*curlun)->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
 		return -EINVAL;
 	}
 
@@ -1189,14 +1192,14 @@ static int do_read_header(struct fsg_common *common, struct fsg_buffhd *bh)
 
 static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh)
 {
-	struct fsg_lun	*curlun = common->curlun;
+	struct fsg_lun	**curlun = common->curlun;
 	int		msf = common->cmnd[1] & 0x02;
 	int		start_track = common->cmnd[6];
 	u8		*buf = (u8 *)bh->buf;
 
 	if ((common->cmnd[1] & ~0x02) != 0 ||	/* Mask away MSF */
 			start_track > 1) {
-		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		(*curlun)->sense_data = SS_INVALID_FIELD_IN_CDB;
 		return -EINVAL;
 	}
 
@@ -1210,13 +1213,13 @@ static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh)
 
 	buf[13] = 0x16;			/* Lead-out track is data */
 	buf[14] = 0xAA;			/* Lead-out track number */
-	store_cdrom_address(&buf[16], msf, curlun->num_sectors);
+	store_cdrom_address(&buf[16], msf, (*curlun)->num_sectors);
 	return 20;
 }
 
 static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
 {
-	struct fsg_lun	*curlun = common->curlun;
+	struct fsg_lun	**curlun = common->curlun;
 	int		mscmnd = common->cmnd[0];
 	u8		*buf = (u8 *) bh->buf;
 	u8		*buf0 = buf;
@@ -1226,13 +1229,13 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
 	int		len, limit;
 
 	if ((common->cmnd[1] & ~0x08) != 0) {	/* Mask away DBD */
-		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		(*curlun)->sense_data = SS_INVALID_FIELD_IN_CDB;
 		return -EINVAL;
 	}
 	pc = common->cmnd[2] >> 6;
 	page_code = common->cmnd[2] & 0x3f;
 	if (pc == 3) {
-		curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED;
+		(*curlun)->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED;
 		return -EINVAL;
 	}
 	changeable_values = (pc == 1);
@@ -1246,11 +1249,11 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
 	 */
 	memset(buf, 0, 8);
 	if (mscmnd == MODE_SENSE) {
-		buf[2] = (curlun->ro ? 0x80 : 0x00);		/* WP, DPOFUA */
+		buf[2] = ((*curlun)->ro ? 0x80 : 0x00);		/* WP, DPOFUA */
 		buf += 4;
 		limit = 255;
 	} else {			/* MODE_SENSE_10 */
-		buf[3] = (curlun->ro ? 0x80 : 0x00);		/* WP, DPOFUA */
+		buf[3] = ((*curlun)->ro ? 0x80 : 0x00);		/* WP, DPOFUA */
 		buf += 8;
 		limit = 65535;		/* Should really be FSG_BUFLEN */
 	}
@@ -1288,7 +1291,7 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
 	 */
 	len = buf - buf0;
 	if (!valid_page || len > limit) {
-		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		(*curlun)->sense_data = SS_INVALID_FIELD_IN_CDB;
 		return -EINVAL;
 	}
 
@@ -1302,17 +1305,17 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
 
 static int do_start_stop(struct fsg_common *common)
 {
-	struct fsg_lun	*curlun = common->curlun;
+	struct fsg_lun	**curlun = common->curlun;
 	int		loej, start;
 
-	if (!curlun) {
+	if (!*curlun) {
 		return -EINVAL;
-	} else if (!curlun->removable) {
-		curlun->sense_data = SS_INVALID_COMMAND;
+	} else if (!(*curlun)->removable) {
+		(*curlun)->sense_data = SS_INVALID_COMMAND;
 		return -EINVAL;
 	} else if ((common->cmnd[1] & ~0x01) != 0 || /* Mask away Immed */
 		   (common->cmnd[4] & ~0x03) != 0) { /* Mask LoEj, Start */
-		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		(*curlun)->sense_data = SS_INVALID_FIELD_IN_CDB;
 		return -EINVAL;
 	}
 
@@ -1324,17 +1327,17 @@ static int do_start_stop(struct fsg_common *common)
 	 * available for use as soon as it is loaded.
 	 */
 	if (start) {
-		if (!fsg_lun_is_open(curlun)) {
-			curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
+		if (!fsg_lun_is_open(*curlun)) {
+			(*curlun)->sense_data = SS_MEDIUM_NOT_PRESENT;
 			return -EINVAL;
 		}
 		return 0;
 	}
 
 	/* Are we allowed to unload the media? */
-	if (curlun->prevent_medium_removal) {
-		LDBG(curlun, "unload attempt prevented\n");
-		curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
+	if ((*curlun)->prevent_medium_removal) {
+		LDBG(*curlun, "unload attempt prevented\n");
+		(*curlun)->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
 		return -EINVAL;
 	}
 
@@ -1343,7 +1346,7 @@ static int do_start_stop(struct fsg_common *common)
 
 	up_read(&common->filesem);
 	down_write(&common->filesem);
-	fsg_lun_close(curlun);
+	fsg_lun_close(*curlun);
 	up_write(&common->filesem);
 	down_read(&common->filesem);
 
@@ -1352,52 +1355,52 @@ static int do_start_stop(struct fsg_common *common)
 
 static int do_prevent_allow(struct fsg_common *common)
 {
-	struct fsg_lun	*curlun = common->curlun;
+	struct fsg_lun	**curlun = common->curlun;
 	int		prevent;
 
 	if (!common->curlun) {
 		return -EINVAL;
-	} else if (!common->curlun->removable) {
-		common->curlun->sense_data = SS_INVALID_COMMAND;
+	} else if (!(*common->curlun)->removable) {
+		(*common->curlun)->sense_data = SS_INVALID_COMMAND;
 		return -EINVAL;
 	}
 
 	prevent = common->cmnd[4] & 0x01;
 	if ((common->cmnd[4] & ~0x01) != 0) {	/* Mask away Prevent */
-		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+		(*curlun)->sense_data = SS_INVALID_FIELD_IN_CDB;
 		return -EINVAL;
 	}
 
-	if (curlun->prevent_medium_removal && !prevent)
-		fsg_lun_fsync_sub(curlun);
-	curlun->prevent_medium_removal = prevent;
+	if ((*curlun)->prevent_medium_removal && !prevent)
+		fsg_lun_fsync_sub(*curlun);
+	(*curlun)->prevent_medium_removal = prevent;
 	return 0;
 }
 
 static int do_read_format_capacities(struct fsg_common *common,
 			struct fsg_buffhd *bh)
 {
-	struct fsg_lun	*curlun = common->curlun;
+	struct fsg_lun	**curlun = common->curlun;
 	u8		*buf = (u8 *) bh->buf;
 
 	buf[0] = buf[1] = buf[2] = 0;
 	buf[3] = 8;	/* Only the Current/Maximum Capacity Descriptor */
 	buf += 4;
 
-	put_unaligned_be32(curlun->num_sectors, &buf[0]);
+	put_unaligned_be32((*curlun)->num_sectors, &buf[0]);
 						/* Number of blocks */
-	put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */
+	put_unaligned_be32((*curlun)->blksize, &buf[4]);/* Block length */
 	buf[4] = 0x02;				/* Current capacity */
 	return 12;
 }
 
 static int do_mode_select(struct fsg_common *common, struct fsg_buffhd *bh)
 {
-	struct fsg_lun	*curlun = common->curlun;
+	struct fsg_lun	**curlun = common->curlun;
 
 	/* We don't support MODE SELECT */
-	if (curlun)
-		curlun->sense_data = SS_INVALID_COMMAND;
+	if (*curlun)
+		(*curlun)->sense_data = SS_INVALID_COMMAND;
 	return -EINVAL;
 }
 
@@ -1607,7 +1610,7 @@ static int finish_reply(struct fsg_common *common)
 
 static int send_status(struct fsg_common *common)
 {
-	struct fsg_lun		*curlun = common->curlun;
+	struct fsg_lun		**curlun = common->curlun;
 	struct fsg_buffhd	*bh;
 	struct bulk_cs_wrap	*csw;
 	int			rc;
@@ -1622,9 +1625,9 @@ static int send_status(struct fsg_common *common)
 			return rc;
 	}
 
-	if (curlun) {
-		sd = curlun->sense_data;
-		sdinfo = curlun->sense_data_info;
+	if (*curlun) {
+		sd = (*curlun)->sense_data;
+		sdinfo = (*curlun)->sense_data_info;
 	} else if (common->bad_lun_okay)
 		sd = SS_NO_SENSE;
 	else
@@ -1675,7 +1678,7 @@ static int check_command(struct fsg_common *common, int cmnd_size,
 	unsigned int		lun = common->cmnd[1] >> 5;
 	static const char	dirletter[4] = {'u', 'o', 'i', 'n'};
 	char			hdlen[20];
-	struct fsg_lun		*curlun;
+	struct fsg_lun		**curlun;
 
 	hdlen[0] = 0;
 	if (common->data_dir != DATA_DIR_UNKNOWN)
@@ -1743,11 +1746,11 @@ static int check_command(struct fsg_common *common, int cmnd_size,
 
 	/* Check the LUN */
 	curlun = common->curlun;
-	if (curlun) {
+	if (*curlun) {
 		if (common->cmnd[0] != REQUEST_SENSE) {
-			curlun->sense_data = SS_NO_SENSE;
-			curlun->sense_data_info = 0;
-			curlun->info_valid = 0;
+			(*curlun)->sense_data = SS_NO_SENSE;
+			(*curlun)->sense_data_info = 0;
+			(*curlun)->info_valid = 0;
 		}
 	} else {
 		common->bad_lun_okay = 0;
@@ -1767,11 +1770,11 @@ static int check_command(struct fsg_common *common, int cmnd_size,
 	 * If a unit attention condition exists, only INQUIRY and
 	 * REQUEST SENSE commands are allowed; anything else must fail.
 	 */
-	if (curlun && curlun->unit_attention_data != SS_NO_SENSE &&
+	if (*curlun && (*curlun)->unit_attention_data != SS_NO_SENSE &&
 	    common->cmnd[0] != INQUIRY &&
 	    common->cmnd[0] != REQUEST_SENSE) {
-		curlun->sense_data = curlun->unit_attention_data;
-		curlun->unit_attention_data = SS_NO_SENSE;
+		(*curlun)->sense_data = (*curlun)->unit_attention_data;
+		(*curlun)->unit_attention_data = SS_NO_SENSE;
 		return -EINVAL;
 	}
 
@@ -1779,16 +1782,16 @@ static int check_command(struct fsg_common *common, int cmnd_size,
 	common->cmnd[1] &= 0x1f;			/* Mask away the LUN */
 	for (i = 1; i < cmnd_size; ++i) {
 		if (common->cmnd[i] && !(mask & (1 << i))) {
-			if (curlun)
-				curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+			if (*curlun)
+				(*curlun)->sense_data = SS_INVALID_FIELD_IN_CDB;
 			return -EINVAL;
 		}
 	}
 
 	/* If the medium isn't mounted and the command needs to access
 	 * it, return an error. */
-	if (curlun && !fsg_lun_is_open(curlun) && needs_medium) {
-		curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
+	if (*curlun && !fsg_lun_is_open(*curlun) && needs_medium) {
+		(*curlun)->sense_data = SS_MEDIUM_NOT_PRESENT;
 		return -EINVAL;
 	}
 
@@ -1800,8 +1803,8 @@ static int check_command_size_in_blocks(struct fsg_common *common,
 		int cmnd_size, enum data_direction data_dir,
 		unsigned int mask, int needs_medium, const char *name)
 {
-	if (common->curlun)
-		common->data_size_from_cmnd <<= common->curlun->blkbits;
+	if (*common->curlun)
+		common->data_size_from_cmnd <<= (*common->curlun)->blkbits;
 	return check_command(common, cmnd_size, data_dir,
 			mask, needs_medium, name);
 }
@@ -1929,7 +1932,7 @@ static int do_scsi_command(struct fsg_common *common)
 		break;
 
 	case READ_HEADER:
-		if (!common->curlun || !common->curlun->cdrom)
+		if (!*common->curlun || !(*common->curlun)->cdrom)
 			goto unknown_cmnd;
 		common->data_size_from_cmnd =
 			get_unaligned_be16(&common->cmnd[7]);
@@ -1941,7 +1944,7 @@ static int do_scsi_command(struct fsg_common *common)
 		break;
 
 	case READ_TOC:
-		if (!common->curlun || !common->curlun->cdrom)
+		if (!*common->curlun || !(*common->curlun)->cdrom)
 			goto unknown_cmnd;
 		common->data_size_from_cmnd =
 			get_unaligned_be16(&common->cmnd[7]);
@@ -2061,7 +2064,7 @@ unknown_cmnd:
 		reply = check_command(common, common->cmnd_size,
 				      DATA_DIR_UNKNOWN, ~0, 0, unknown);
 		if (reply == 0) {
-			common->curlun->sense_data = SS_INVALID_COMMAND;
+			(*common->curlun)->sense_data = SS_INVALID_COMMAND;
 			reply = -EINVAL;
 		}
 		break;
@@ -2297,7 +2300,9 @@ reset:
 
 	common->running = 1;
 	for (i = 0; i < common->nluns; ++i)
-		common->luns[i].unit_attention_data = SS_RESET_OCCURRED;
+		if (common->luns[i])
+			common->luns[i]->unit_attention_data =
+				SS_RESET_OCCURRED;
 	return rc;
 }
 
@@ -2397,7 +2402,9 @@ static void handle_exception(struct fsg_common *common)
 		common->state = FSG_STATE_STATUS_PHASE;
 	else {
 		for (i = 0; i < common->nluns; ++i) {
-			curlun = &common->luns[i];
+			curlun = common->luns[i];
+			if (!curlun)
+				continue;
 			curlun->prevent_medium_removal = 0;
 			curlun->sense_data = SS_NO_SENSE;
 			curlun->unit_attention_data = SS_NO_SENSE;
@@ -2439,7 +2446,7 @@ static void handle_exception(struct fsg_common *common)
 		 * CONFIG_CHANGE cases.
 		 */
 		/* for (i = 0; i < common->nluns; ++i) */
-		/*	common->luns[i].unit_attention_data = */
+		/*	common->luns[i]->unit_attention_data = */
 		/*		SS_RESET_OCCURRED;  */
 		break;
 
@@ -2536,16 +2543,16 @@ static int fsg_main_thread(void *common_)
 
 	if (!common->ops || !common->ops->thread_exits
 	 || common->ops->thread_exits(common) < 0) {
-		struct fsg_lun *curlun = common->luns;
+		struct fsg_lun **curlun = common->luns;
 		unsigned i = common->nluns;
 
 		down_write(&common->filesem);
 		for (; i--; ++curlun) {
-			if (!fsg_lun_is_open(curlun))
+			if (!*curlun || !fsg_lun_is_open(*curlun))
 				continue;
 
-			fsg_lun_close(curlun);
-			curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
+			fsg_lun_close(*curlun);
+			(*curlun)->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
 		}
 		up_write(&common->filesem);
 	}
@@ -2602,7 +2609,7 @@ struct fsg_common *fsg_common_init(struct fsg_common *common,
 {
 	struct usb_gadget *gadget = cdev->gadget;
 	struct fsg_buffhd *bh;
-	struct fsg_lun *curlun;
+	struct fsg_lun **curlun;
 	struct fsg_lun_config *lcfg;
 	int nluns, i, rc;
 	char *pathbuf;
@@ -2669,45 +2676,52 @@ struct fsg_common *fsg_common_init(struct fsg_common *common,
 	init_rwsem(&common->filesem);
 
 	for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun, ++lcfg) {
-		curlun->cdrom = !!lcfg->cdrom;
-		curlun->ro = lcfg->cdrom || lcfg->ro;
-		curlun->initially_ro = curlun->ro;
-		curlun->removable = lcfg->removable;
-		curlun->dev.release = fsg_lun_release;
-		curlun->dev.parent = &gadget->dev;
-		/* curlun->dev.driver = &fsg_driver.driver; XXX */
-		dev_set_drvdata(&curlun->dev, &common->filesem);
-		dev_set_name(&curlun->dev, "lun%d", i);
-
-		rc = device_register(&curlun->dev);
+		*curlun = kzalloc(sizeof(**curlun), GFP_KERNEL);
+		if (!*curlun) {
+			rc = -ENOMEM;
+			common->nluns = i;
+			goto error_release;
+		}
+		(*curlun)->cdrom = !!lcfg->cdrom;
+		(*curlun)->ro = lcfg->cdrom || lcfg->ro;
+		(*curlun)->initially_ro = (*curlun)->ro;
+		(*curlun)->removable = lcfg->removable;
+		(*curlun)->dev.release = fsg_lun_release;
+		(*curlun)->dev.parent = &gadget->dev;
+		/* (curlun*)->dev.driver = &fsg_driver.driver; XXX */
+		dev_set_drvdata(&(*curlun)->dev, &common->filesem);
+		dev_set_name(&(*curlun)->dev, "lun%d", i);
+
+		rc = device_register(&(*curlun)->dev);
 		if (rc) {
 			INFO(common, "failed to register LUN%d: %d\n", i, rc);
 			common->nluns = i;
-			put_device(&curlun->dev);
+			put_device(&(*curlun)->dev);
+			kfree(*curlun);
 			goto error_release;
 		}
 
-		rc = device_create_file(&curlun->dev,
-					curlun->cdrom
+		rc = device_create_file(&(*curlun)->dev,
+					(*curlun)->cdrom
 				      ? &dev_attr_ro_cdrom
 				      : &dev_attr_ro);
 		if (rc)
 			goto error_luns;
-		rc = device_create_file(&curlun->dev,
-					curlun->removable
+		rc = device_create_file(&(*curlun)->dev,
+					(*curlun)->removable
 				      ? &dev_attr_file
 				      : &dev_attr_file_nonremovable);
 		if (rc)
 			goto error_luns;
-		rc = device_create_file(&curlun->dev, &dev_attr_nofua);
+		rc = device_create_file(&(*curlun)->dev, &dev_attr_nofua);
 		if (rc)
 			goto error_luns;
 
 		if (lcfg->filename) {
-			rc = fsg_lun_open(curlun, lcfg->filename);
+			rc = fsg_lun_open(*curlun, lcfg->filename);
 			if (rc)
 				goto error_luns;
-		} else if (!curlun->removable) {
+		} else if (!(*curlun)->removable) {
 			ERROR(common, "no file given for LUN%d\n", i);
 			rc = -EINVAL;
 			goto error_luns;
@@ -2736,7 +2750,7 @@ buffhds_first_it:
 	snprintf(common->inquiry_string, sizeof common->inquiry_string,
 		 "%-8s%-16s%04x", cfg->vendor_name ?: "Linux",
 		 /* Assume product name dependent on the first LUN */
-		 cfg->product_name ?: (common->luns->cdrom
+		 cfg->product_name ?: ((*common->luns)->cdrom
 				     ? "File-CD Gadget"
 				     : "File-Stor Gadget"),
 		 i);
@@ -2771,19 +2785,19 @@ buffhds_first_it:
 	     i < nluns;
 	     ++curlun, ++i) {
 		char *p = "(no medium)";
-		if (fsg_lun_is_open(curlun)) {
+		if (fsg_lun_is_open(*curlun)) {
 			p = "(error)";
 			if (pathbuf) {
-				p = d_path(&curlun->filp->f_path,
+				p = d_path(&(*curlun)->filp->f_path,
 					   pathbuf, PATH_MAX);
 				if (IS_ERR(p))
 					p = "(error)";
 			}
 		}
-		LINFO(curlun, "LUN: %s%s%sfile: %s\n",
-		      curlun->removable ? "removable " : "",
-		      curlun->ro ? "read only " : "",
-		      curlun->cdrom ? "CD-ROM " : "",
+		LINFO(*curlun, "LUN: %s%s%sfile: %s\n",
+		      (*curlun)->removable ? "removable " : "",
+		      (*curlun)->ro ? "read only " : "",
+		      (*curlun)->cdrom ? "CD-ROM " : "",
 		      p);
 	}
 	kfree(pathbuf);
@@ -2814,22 +2828,25 @@ static void fsg_common_release(struct kref *ref)
 	}
 
 	if (likely(common->luns)) {
-		struct fsg_lun *lun = common->luns;
+		struct fsg_lun **lun = common->luns;
 		unsigned i = common->nluns;
 
 		/* In error recovery common->nluns may be zero. */
 		for (; i; --i, ++lun) {
-			device_remove_file(&lun->dev, &dev_attr_nofua);
-			device_remove_file(&lun->dev,
-					   lun->cdrom
+			if (!*lun)
+				continue;
+			device_remove_file(&(*lun)->dev, &dev_attr_nofua);
+			device_remove_file(&(*lun)->dev,
+					   (*lun)->cdrom
 					 ? &dev_attr_ro_cdrom
 					 : &dev_attr_ro);
-			device_remove_file(&lun->dev,
-					   lun->removable
+			device_remove_file(&(*lun)->dev,
+					   (*lun)->removable
 					 ? &dev_attr_file
 					 : &dev_attr_file_nonremovable);
-			fsg_lun_close(lun);
-			device_unregister(&lun->dev);
+			fsg_lun_close(*lun);
+			device_unregister(&(*lun)->dev);
+			kfree(*lun);
 		}
 
 		kfree(common->luns);
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux