⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 file_storage.c

📁 h内核
💻 C
📖 第 1 页 / 共 5 页
字号:
			continue;		}		/* Write the received data to the backing file */		bh = fsg->next_buffhd_to_drain;		if (bh->state == BUF_STATE_EMPTY && !get_some_more)			break;			// We stopped early		if (bh->state == BUF_STATE_FULL) {			fsg->next_buffhd_to_drain = bh->next;			bh->state = BUF_STATE_EMPTY;			/* Did something go wrong with the transfer? */			if (bh->outreq->status != 0) {				curlun->sense_data = SS_COMMUNICATION_FAILURE;				curlun->sense_data_info = file_offset >> 9;				break;			}			amount = bh->outreq->actual;			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;			}			/* Perform the write */			file_offset_tmp = file_offset;			nwritten = vfs_write(curlun->filp,					(char __user *) bh->buf,					amount, &file_offset_tmp);			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",						(int) nwritten);				nwritten = 0;			} else if (nwritten < amount) {				LDBG(curlun, "partial file write: %d/%u\n",						(int) nwritten, amount);				nwritten -= (nwritten & 511);						// Round down to a block			}			file_offset += nwritten;			amount_left_to_write -= nwritten;			fsg->residue -= nwritten;			/* If an error occurred, report it and its position */			if (nwritten < amount) {				curlun->sense_data = SS_WRITE_ERROR;				curlun->sense_data_info = file_offset >> 9;				break;			}			/* Did the host decide to stop early? */			if (bh->outreq->actual != bh->outreq->length) {				fsg->short_packet_received = 1;				break;			}			continue;		}		/* Wait for something to happen */		if ((rc = sleep_thread(fsg)) != 0)			return rc;	}	return -EIO;		// No default reply}/*-------------------------------------------------------------------------*//* Sync the file data, don't bother with the metadata. * This code was copied from fs/buffer.c:sys_fdatasync(). */static int fsync_sub(struct lun *curlun){	struct file	*filp = curlun->filp;	struct inode	*inode;	int		rc, err;	if (curlun->ro || !filp)		return 0;	if (!filp->f_op->fsync)		return -EINVAL;	inode = filp->f_dentry->d_inode;	down(&inode->i_sem);	current->flags |= PF_SYNCWRITE;	rc = filemap_fdatawrite(inode->i_mapping);	err = filp->f_op->fsync(filp, filp->f_dentry, 1);	if (!rc)		rc = err;	err = filemap_fdatawait(inode->i_mapping);	if (!rc)		rc = err;	current->flags &= ~PF_SYNCWRITE;	up(&inode->i_sem);	VLDBG(curlun, "fdatasync -> %d\n", rc);	return rc;}static void fsync_all(struct fsg_dev *fsg){	int	i;	for (i = 0; i < fsg->nluns; ++i)		fsync_sub(&fsg->luns[i]);}static int do_synchronize_cache(struct fsg_dev *fsg){	struct lun	*curlun = fsg->curlun;	int		rc;	/* We ignore the requested LBA and write out all file's	 * dirty data buffers. */	rc = fsync_sub(curlun);	if (rc)		curlun->sense_data = SS_WRITE_ERROR;	return 0;}/*-------------------------------------------------------------------------*/static void invalidate_sub(struct lun *curlun){	struct file	*filp = curlun->filp;	struct inode	*inode = filp->f_dentry->d_inode;	unsigned long	rc;	rc = invalidate_inode_pages(inode->i_mapping);	VLDBG(curlun, "invalidate_inode_pages -> %ld\n", rc);}static int do_verify(struct fsg_dev *fsg){	struct lun		*curlun = fsg->curlun;	u32			lba;	u32			verification_length;	struct fsg_buffhd	*bh = fsg->next_buffhd_to_fill;	loff_t			file_offset, file_offset_tmp;	u32			amount_left;	unsigned int		amount;	ssize_t			nread;	/* Get the starting Logical Block Address and check that it's	 * not too big */	lba = get_be32(&fsg->cmnd[2]);	if (lba >= curlun->num_sectors) {		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;		return -EINVAL;	}	/* We allow DPO (Disable Page Out = don't save data in the	 * cache) but we don't implement it. */	if ((fsg->cmnd[1] & ~0x10) != 0) {		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;		return -EINVAL;	}	verification_length = get_be16(&fsg->cmnd[7]);	if (unlikely(verification_length == 0))		return -EIO;		// No default reply	/* Prepare to carry out the file verify */	amount_left = verification_length << 9;	file_offset = ((loff_t) lba) << 9;	/* Write out all the dirty buffers before invalidating them */	fsync_sub(curlun);	if (signal_pending(current))		return -EINTR;	invalidate_sub(curlun);	if (signal_pending(current))		return -EINTR;	/* Just try to read the requested blocks */	while (amount_left > 0) {		/* Figure out how much we need to read:		 * Try to read the remaining amount, but not more than		 * the buffer size.		 * And don't try to read past the end of the file.		 * If this means reading 0 then we were asked to read		 * past the end of file. */		amount = min((unsigned int) amount_left, mod_data.buflen);		amount = min((loff_t) amount,				curlun->file_length - file_offset);		if (amount == 0) {			curlun->sense_data =					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;			curlun->sense_data_info = file_offset >> 9;			break;		}		/* Perform the read */		file_offset_tmp = file_offset;		nread = vfs_read(curlun->filp,				(char __user *) bh->buf,				amount, &file_offset_tmp);		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);			nread = 0;		} else if (nread < amount) {			LDBG(curlun, "partial file verify: %d/%u\n",					(int) nread, amount);			nread -= (nread & 511);	// Round down to a sector		}		if (nread == 0) {			curlun->sense_data = SS_UNRECOVERED_READ_ERROR;			curlun->sense_data_info = file_offset >> 9;			break;		}		file_offset += nread;		amount_left -= nread;	}	return 0;}/*-------------------------------------------------------------------------*/static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh){	u8	*buf = (u8 *) bh->buf;	static char vendor_id[] = "Linux   ";	static char product_id[] = "File-Stor Gadget";	if (!fsg->curlun) {		// Unsupported LUNs are okay		fsg->bad_lun_okay = 1;		memset(buf, 0, 36);		buf[0] = 0x7f;		// Unsupported, no device-type		return 36;	}	memset(buf, 0, 8);	// Non-removable, direct-access device	if (mod_data.removable)		buf[1] = 0x80;	buf[2] = 2;		// ANSI SCSI level 2	buf[3] = 2;		// SCSI-2 INQUIRY data format	buf[4] = 31;		// Additional length				// No special options	sprintf(buf + 8, "%-8s%-16s%04x", vendor_id, product_id,			mod_data.release);	return 36;}static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh){	struct lun	*curlun = fsg->curlun;	u8		*buf = (u8 *) bh->buf;	u32		sd, sdinfo;	/*	 * From the SCSI-2 spec., section 7.9 (Unit attention condition):	 *	 * If a REQUEST SENSE command is received from an initiator	 * with a pending unit attention condition (before the target	 * generates the contingent allegiance condition), then the	 * target shall either:	 *   a) report any pending sense data and preserve the unit	 *	attention condition on the logical unit, or,	 *   b) report the unit attention condition, may discard any	 *	pending sense data, and clear the unit attention	 *	condition on the logical unit for that initiator.	 *	 * 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;	}#endif	if (!curlun) {		// Unsupported LUNs are okay		fsg->bad_lun_okay = 1;		sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;		sdinfo = 0;	} else {		sd = curlun->sense_data;		sdinfo = curlun->sense_data_info;		curlun->sense_data = SS_NO_SENSE;		curlun->sense_data_info = 0;	}	memset(buf, 0, 18);	buf[0] = 0x80 | 0x70;			// Valid, current error	buf[2] = SK(sd);	put_be32(&buf[3], sdinfo);		// Sense information	buf[7] = 18 - 8;			// Additional sense length	buf[12] = ASC(sd);	buf[13] = ASCQ(sd);	return 18;}static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh){	struct lun	*curlun = fsg->curlun;	u32		lba = get_be32(&fsg->cmnd[2]);	int		pmi = fsg->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;		return -EINVAL;	}	put_be32(&buf[0], curlun->num_sectors - 1);	// Max logical block	put_be32(&buf[4], 512);				// Block length	return 8;}static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh){	struct lun	*curlun = fsg->curlun;	int		mscmnd = fsg->cmnd[0];	u8		*buf = (u8 *) bh->buf;	u8		*buf0 = buf;	int		pc, page_code;	int		changeable_values, all_pages;	int		valid_page = 0;	int		len, limit;	if ((fsg->cmnd[1] & ~0x08) != 0) {		// Mask away DBD		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;		return -EINVAL;	}	pc = fsg->cmnd[2] >> 6;	page_code = fsg->cmnd[2] & 0x3f;	if (pc == 3) {		curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED;		return -EINVAL;	}	changeable_values = (pc == 1);	all_pages = (page_code == 0x3f);	/* Write the mode parameter header.  Fixed values are: default	 * medium type, no cache control (DPOFUA), and no block descriptors.	 * The only variable value is the WriteProtect bit.  We will fill in	 * the mode data length later. */	memset(buf, 0, 8);	if (mscmnd == SC_MODE_SENSE_6) {		buf[2] = (curlun->ro ? 0x80 : 0x00);		// WP, DPOFUA		buf += 4;		limit = 255;	} else {			// SC_MODE_SENSE_10		buf[3] = (curlun->ro ? 0x80 : 0x00);		// WP, DPOFUA		buf += 8;		limit = 65535;		// Should really be mod_data.buflen	}	/* No block descriptors */	/* The mode pages, in numerical order.  The only page we support	 * is the Caching page. */	if (page_code == 0x08 || all_pages) {		valid_page = 1;		buf[0] = 0x08;		// Page code		buf[1] = 10;		// Page length		memset(buf+2, 0, 10);	// None of the fields are changeable		if (!changeable_values) {			buf[2] = 0x04;	// Write cache enable,					// Read cache not disabled					// No cache retention priorities			put_be16(&buf[4], 0xffff);  // Don't disable prefetch					// Minimum prefetch = 0			put_be16(&buf[8], 0xffff);  // Maximum prefetch			put_be16(&buf[10], 0xffff); // Maximum prefetch ceiling		}		buf += 12;	}	/* Check that a valid page was requested and the mode data length	 * isn't too long. */	len = buf - buf0;	if (!valid_page || len > limit) {		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;		return -EINVAL;	}	/*  Store the mode data length */	if (mscmnd == SC_MODE_SENSE_6)		buf0[0] = len - 1;	else		put_be16(buf0, len - 2);	return len;}static int do_start_stop(struct fsg_dev *fsg){	struct lun	*curlun = fsg->curlun;	int		loej, start;	if (!mod_data.removable) {		curlun->sense_data = SS_INVALID_COMMAND;		return -EINVAL;	}	// int immed = fsg->cmnd[1] & 0x01;	loej = fsg->cmnd[4] & 0x02;	start = fsg->cmnd[4] & 0x01;#ifdef CONFIG_USB_FILE_STORAGE_TEST	if ((fsg->cmnd[1] & ~0x01) != 0 ||		// Mask away Immed			(fsg->cmnd[4] & ~0x03) != 0) {	// Mask LoEj, Start		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;		return -EINVAL;	}	if (!start) {		/* 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;			return -EINVAL;		}		if (loej) {		// Simulate an unload/eject			up_read(&fsg->filesem);			down_write(&fsg->filesem);			close_backin

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -