brintos

brintos / linux-shallow public Read only

0
0
Text · 24.2 KiB · 2d78ef7 Raw
951 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*******************************************************************************3 * Filename:  target_core_file.c4 *5 * This file contains the Storage Engine <-> FILEIO transport specific functions6 *7 * (c) Copyright 2005-2013 Datera, Inc.8 *9 * Nicholas A. Bellinger <nab@kernel.org>10 *11 ******************************************************************************/12 13#include <linux/string.h>14#include <linux/parser.h>15#include <linux/timer.h>16#include <linux/blkdev.h>17#include <linux/slab.h>18#include <linux/spinlock.h>19#include <linux/module.h>20#include <linux/vmalloc.h>21#include <linux/falloc.h>22#include <linux/uio.h>23#include <linux/scatterlist.h>24#include <scsi/scsi_proto.h>25#include <linux/unaligned.h>26 27#include <target/target_core_base.h>28#include <target/target_core_backend.h>29 30#include "target_core_file.h"31 32static inline struct fd_dev *FD_DEV(struct se_device *dev)33{34	return container_of(dev, struct fd_dev, dev);35}36 37static int fd_attach_hba(struct se_hba *hba, u32 host_id)38{39	struct fd_host *fd_host;40 41	fd_host = kzalloc(sizeof(struct fd_host), GFP_KERNEL);42	if (!fd_host) {43		pr_err("Unable to allocate memory for struct fd_host\n");44		return -ENOMEM;45	}46 47	fd_host->fd_host_id = host_id;48 49	hba->hba_ptr = fd_host;50 51	pr_debug("CORE_HBA[%d] - TCM FILEIO HBA Driver %s on Generic"52		" Target Core Stack %s\n", hba->hba_id, FD_VERSION,53		TARGET_CORE_VERSION);54	pr_debug("CORE_HBA[%d] - Attached FILEIO HBA: %u to Generic\n",55		hba->hba_id, fd_host->fd_host_id);56 57	return 0;58}59 60static void fd_detach_hba(struct se_hba *hba)61{62	struct fd_host *fd_host = hba->hba_ptr;63 64	pr_debug("CORE_HBA[%d] - Detached FILEIO HBA: %u from Generic"65		" Target Core\n", hba->hba_id, fd_host->fd_host_id);66 67	kfree(fd_host);68	hba->hba_ptr = NULL;69}70 71static struct se_device *fd_alloc_device(struct se_hba *hba, const char *name)72{73	struct fd_dev *fd_dev;74	struct fd_host *fd_host = hba->hba_ptr;75 76	fd_dev = kzalloc(sizeof(struct fd_dev), GFP_KERNEL);77	if (!fd_dev) {78		pr_err("Unable to allocate memory for struct fd_dev\n");79		return NULL;80	}81 82	fd_dev->fd_host = fd_host;83 84	pr_debug("FILEIO: Allocated fd_dev for %p\n", name);85 86	return &fd_dev->dev;87}88 89static bool fd_configure_unmap(struct se_device *dev)90{91	struct file *file = FD_DEV(dev)->fd_file;92	struct inode *inode = file->f_mapping->host;93 94	if (S_ISBLK(inode->i_mode))95		return target_configure_unmap_from_queue(&dev->dev_attrib,96							 I_BDEV(inode));97 98	/* Limit UNMAP emulation to 8k Number of LBAs (NoLB) */99	dev->dev_attrib.max_unmap_lba_count = 0x2000;100	/* Currently hardcoded to 1 in Linux/SCSI code. */101	dev->dev_attrib.max_unmap_block_desc_count = 1;102	dev->dev_attrib.unmap_granularity = 1;103	dev->dev_attrib.unmap_granularity_alignment = 0;104	return true;105}106 107static int fd_configure_device(struct se_device *dev)108{109	struct fd_dev *fd_dev = FD_DEV(dev);110	struct fd_host *fd_host = dev->se_hba->hba_ptr;111	struct file *file;112	struct inode *inode = NULL;113	int flags, ret = -EINVAL;114 115	if (!(fd_dev->fbd_flags & FBDF_HAS_PATH)) {116		pr_err("Missing fd_dev_name=\n");117		return -EINVAL;118	}119 120	/*121	 * Use O_DSYNC by default instead of O_SYNC to forgo syncing122	 * of pure timestamp updates.123	 */124	flags = O_RDWR | O_CREAT | O_LARGEFILE | O_DSYNC;125 126	/*127	 * Optionally allow fd_buffered_io=1 to be enabled for people128	 * who want use the fs buffer cache as an WriteCache mechanism.129	 *130	 * This means that in event of a hard failure, there is a risk131	 * of silent data-loss if the SCSI client has *not* performed a132	 * forced unit access (FUA) write, or issued SYNCHRONIZE_CACHE133	 * to write-out the entire device cache.134	 */135	if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) {136		pr_debug("FILEIO: Disabling O_DSYNC, using buffered FILEIO\n");137		flags &= ~O_DSYNC;138	}139 140	file = filp_open(fd_dev->fd_dev_name, flags, 0600);141	if (IS_ERR(file)) {142		pr_err("filp_open(%s) failed\n", fd_dev->fd_dev_name);143		ret = PTR_ERR(file);144		goto fail;145	}146	fd_dev->fd_file = file;147	/*148	 * If using a block backend with this struct file, we extract149	 * fd_dev->fd_[block,dev]_size from struct block_device.150	 *151	 * Otherwise, we use the passed fd_size= from configfs152	 */153	inode = file->f_mapping->host;154	if (S_ISBLK(inode->i_mode)) {155		struct block_device *bdev = I_BDEV(inode);156		unsigned long long dev_size;157 158		fd_dev->fd_block_size = bdev_logical_block_size(bdev);159		/*160		 * Determine the number of bytes from i_size_read() minus161		 * one (1) logical sector from underlying struct block_device162		 */163		dev_size = (i_size_read(file->f_mapping->host) -164				       fd_dev->fd_block_size);165 166		pr_debug("FILEIO: Using size: %llu bytes from struct"167			" block_device blocks: %llu logical_block_size: %d\n",168			dev_size, div_u64(dev_size, fd_dev->fd_block_size),169			fd_dev->fd_block_size);170		/*171		 * Enable write same emulation for IBLOCK and use 0xFFFF as172		 * the smaller WRITE_SAME(10) only has a two-byte block count.173		 */174		dev->dev_attrib.max_write_same_len = 0xFFFF;175 176		if (bdev_nonrot(bdev))177			dev->dev_attrib.is_nonrot = 1;178	} else {179		if (!(fd_dev->fbd_flags & FBDF_HAS_SIZE)) {180			pr_err("FILEIO: Missing fd_dev_size="181				" parameter, and no backing struct"182				" block_device\n");183			goto fail;184		}185 186		fd_dev->fd_block_size = FD_BLOCKSIZE;187 188		/*189		 * Limit WRITE_SAME w/ UNMAP=0 emulation to 8k Number of LBAs (NoLB)190		 * based upon struct iovec limit for vfs_writev()191		 */192		dev->dev_attrib.max_write_same_len = 0x1000;193	}194 195	dev->dev_attrib.hw_block_size = fd_dev->fd_block_size;196	dev->dev_attrib.hw_max_sectors = FD_MAX_BYTES / fd_dev->fd_block_size;197	dev->dev_attrib.hw_queue_depth = FD_MAX_DEVICE_QUEUE_DEPTH;198 199	if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) {200		pr_debug("FILEIO: Forcing setting of emulate_write_cache=1"201			" with FDBD_HAS_BUFFERED_IO_WCE\n");202		dev->dev_attrib.emulate_write_cache = 1;203	}204 205	fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++;206	fd_dev->fd_queue_depth = dev->queue_depth;207 208	pr_debug("CORE_FILE[%u] - Added TCM FILEIO Device ID: %u at %s,"209		" %llu total bytes\n", fd_host->fd_host_id, fd_dev->fd_dev_id,210			fd_dev->fd_dev_name, fd_dev->fd_dev_size);211 212	return 0;213fail:214	if (fd_dev->fd_file) {215		filp_close(fd_dev->fd_file, NULL);216		fd_dev->fd_file = NULL;217	}218	return ret;219}220 221static void fd_dev_call_rcu(struct rcu_head *p)222{223	struct se_device *dev = container_of(p, struct se_device, rcu_head);224	struct fd_dev *fd_dev = FD_DEV(dev);225 226	kfree(fd_dev);227}228 229static void fd_free_device(struct se_device *dev)230{231	call_rcu(&dev->rcu_head, fd_dev_call_rcu);232}233 234static void fd_destroy_device(struct se_device *dev)235{236	struct fd_dev *fd_dev = FD_DEV(dev);237 238	if (fd_dev->fd_file) {239		filp_close(fd_dev->fd_file, NULL);240		fd_dev->fd_file = NULL;241	}242}243 244struct target_core_file_cmd {245	unsigned long	len;246	struct se_cmd	*cmd;247	struct kiocb	iocb;248	struct bio_vec	bvecs[];249};250 251static void cmd_rw_aio_complete(struct kiocb *iocb, long ret)252{253	struct target_core_file_cmd *cmd;254 255	cmd = container_of(iocb, struct target_core_file_cmd, iocb);256 257	if (ret != cmd->len)258		target_complete_cmd(cmd->cmd, SAM_STAT_CHECK_CONDITION);259	else260		target_complete_cmd(cmd->cmd, SAM_STAT_GOOD);261 262	kfree(cmd);263}264 265static sense_reason_t266fd_execute_rw_aio(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,267	      enum dma_data_direction data_direction)268{269	int is_write = !(data_direction == DMA_FROM_DEVICE);270	struct se_device *dev = cmd->se_dev;271	struct fd_dev *fd_dev = FD_DEV(dev);272	struct file *file = fd_dev->fd_file;273	struct target_core_file_cmd *aio_cmd;274	struct iov_iter iter;275	struct scatterlist *sg;276	ssize_t len = 0;277	int ret = 0, i;278 279	aio_cmd = kmalloc(struct_size(aio_cmd, bvecs, sgl_nents), GFP_KERNEL);280	if (!aio_cmd)281		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;282 283	for_each_sg(sgl, sg, sgl_nents, i) {284		bvec_set_page(&aio_cmd->bvecs[i], sg_page(sg), sg->length,285			      sg->offset);286		len += sg->length;287	}288 289	iov_iter_bvec(&iter, is_write, aio_cmd->bvecs, sgl_nents, len);290 291	aio_cmd->cmd = cmd;292	aio_cmd->len = len;293	aio_cmd->iocb.ki_pos = cmd->t_task_lba * dev->dev_attrib.block_size;294	aio_cmd->iocb.ki_filp = file;295	aio_cmd->iocb.ki_complete = cmd_rw_aio_complete;296	aio_cmd->iocb.ki_flags = IOCB_DIRECT;297 298	if (is_write && (cmd->se_cmd_flags & SCF_FUA))299		aio_cmd->iocb.ki_flags |= IOCB_DSYNC;300 301	if (is_write)302		ret = file->f_op->write_iter(&aio_cmd->iocb, &iter);303	else304		ret = file->f_op->read_iter(&aio_cmd->iocb, &iter);305 306	if (ret != -EIOCBQUEUED)307		cmd_rw_aio_complete(&aio_cmd->iocb, ret);308 309	return 0;310}311 312static int fd_do_rw(struct se_cmd *cmd, struct file *fd,313		    u32 block_size, struct scatterlist *sgl,314		    u32 sgl_nents, u32 data_length, int is_write)315{316	struct scatterlist *sg;317	struct iov_iter iter;318	struct bio_vec *bvec;319	ssize_t len = 0;320	loff_t pos = (cmd->t_task_lba * block_size);321	int ret = 0, i;322 323	bvec = kcalloc(sgl_nents, sizeof(struct bio_vec), GFP_KERNEL);324	if (!bvec) {325		pr_err("Unable to allocate fd_do_readv iov[]\n");326		return -ENOMEM;327	}328 329	for_each_sg(sgl, sg, sgl_nents, i) {330		bvec_set_page(&bvec[i], sg_page(sg), sg->length, sg->offset);331		len += sg->length;332	}333 334	iov_iter_bvec(&iter, is_write, bvec, sgl_nents, len);335	if (is_write)336		ret = vfs_iter_write(fd, &iter, &pos, 0);337	else338		ret = vfs_iter_read(fd, &iter, &pos, 0);339 340	if (is_write) {341		if (ret < 0 || ret != data_length) {342			pr_err("%s() write returned %d\n", __func__, ret);343			if (ret >= 0)344				ret = -EINVAL;345		}346	} else {347		/*348		 * Return zeros and GOOD status even if the READ did not return349		 * the expected virt_size for struct file w/o a backing struct350		 * block_device.351		 */352		if (S_ISBLK(file_inode(fd)->i_mode)) {353			if (ret < 0 || ret != data_length) {354				pr_err("%s() returned %d, expecting %u for "355						"S_ISBLK\n", __func__, ret,356						data_length);357				if (ret >= 0)358					ret = -EINVAL;359			}360		} else {361			if (ret < 0) {362				pr_err("%s() returned %d for non S_ISBLK\n",363						__func__, ret);364			} else if (ret != data_length) {365				/*366				 * Short read case:367				 * Probably some one truncate file under us.368				 * We must explicitly zero sg-pages to prevent369				 * expose uninizialized pages to userspace.370				 */371				if (ret < data_length)372					ret += iov_iter_zero(data_length - ret, &iter);373				else374					ret = -EINVAL;375			}376		}377	}378	kfree(bvec);379	return ret;380}381 382static sense_reason_t383fd_execute_sync_cache(struct se_cmd *cmd)384{385	struct se_device *dev = cmd->se_dev;386	struct fd_dev *fd_dev = FD_DEV(dev);387	int immed = (cmd->t_task_cdb[1] & 0x2);388	loff_t start, end;389	int ret;390 391	/*392	 * If the Immediate bit is set, queue up the GOOD response393	 * for this SYNCHRONIZE_CACHE op394	 */395	if (immed)396		target_complete_cmd(cmd, SAM_STAT_GOOD);397 398	/*399	 * Determine if we will be flushing the entire device.400	 */401	if (cmd->t_task_lba == 0 && cmd->data_length == 0) {402		start = 0;403		end = LLONG_MAX;404	} else {405		start = cmd->t_task_lba * dev->dev_attrib.block_size;406		if (cmd->data_length)407			end = start + cmd->data_length - 1;408		else409			end = LLONG_MAX;410	}411 412	ret = vfs_fsync_range(fd_dev->fd_file, start, end, 1);413	if (ret != 0)414		pr_err("FILEIO: vfs_fsync_range() failed: %d\n", ret);415 416	if (immed)417		return 0;418 419	if (ret)420		target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION);421	else422		target_complete_cmd(cmd, SAM_STAT_GOOD);423 424	return 0;425}426 427static sense_reason_t428fd_execute_write_same(struct se_cmd *cmd)429{430	struct se_device *se_dev = cmd->se_dev;431	struct fd_dev *fd_dev = FD_DEV(se_dev);432	loff_t pos = cmd->t_task_lba * se_dev->dev_attrib.block_size;433	sector_t nolb = sbc_get_write_same_sectors(cmd);434	struct iov_iter iter;435	struct bio_vec *bvec;436	unsigned int len = 0, i;437	ssize_t ret;438 439	if (cmd->prot_op) {440		pr_err("WRITE_SAME: Protection information with FILEIO"441		       " backends not supported\n");442		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;443	}444 445	if (!cmd->t_data_nents)446		return TCM_INVALID_CDB_FIELD;447 448	if (cmd->t_data_nents > 1 ||449	    cmd->t_data_sg[0].length != cmd->se_dev->dev_attrib.block_size) {450		pr_err("WRITE_SAME: Illegal SGL t_data_nents: %u length: %u"451			" block_size: %u\n",452			cmd->t_data_nents,453			cmd->t_data_sg[0].length,454			cmd->se_dev->dev_attrib.block_size);455		return TCM_INVALID_CDB_FIELD;456	}457 458	bvec = kcalloc(nolb, sizeof(struct bio_vec), GFP_KERNEL);459	if (!bvec)460		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;461 462	for (i = 0; i < nolb; i++) {463		bvec_set_page(&bvec[i], sg_page(&cmd->t_data_sg[0]),464			      cmd->t_data_sg[0].length,465			      cmd->t_data_sg[0].offset);466		len += se_dev->dev_attrib.block_size;467	}468 469	iov_iter_bvec(&iter, ITER_SOURCE, bvec, nolb, len);470	ret = vfs_iter_write(fd_dev->fd_file, &iter, &pos, 0);471 472	kfree(bvec);473	if (ret < 0 || ret != len) {474		pr_err("vfs_iter_write() returned %zd for write same\n", ret);475		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;476	}477 478	target_complete_cmd(cmd, SAM_STAT_GOOD);479	return 0;480}481 482static int483fd_do_prot_fill(struct se_device *se_dev, sector_t lba, sector_t nolb,484		void *buf, size_t bufsize)485{486	struct fd_dev *fd_dev = FD_DEV(se_dev);487	struct file *prot_fd = fd_dev->fd_prot_file;488	sector_t prot_length, prot;489	loff_t pos = lba * se_dev->prot_length;490 491	if (!prot_fd) {492		pr_err("Unable to locate fd_dev->fd_prot_file\n");493		return -ENODEV;494	}495 496	prot_length = nolb * se_dev->prot_length;497 498	memset(buf, 0xff, bufsize);499	for (prot = 0; prot < prot_length;) {500		sector_t len = min_t(sector_t, bufsize, prot_length - prot);501		ssize_t ret = kernel_write(prot_fd, buf, len, &pos);502 503		if (ret != len) {504			pr_err("vfs_write to prot file failed: %zd\n", ret);505			return ret < 0 ? ret : -ENODEV;506		}507		prot += ret;508	}509 510	return 0;511}512 513static int514fd_do_prot_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb)515{516	void *buf;517	int rc;518 519	buf = (void *)__get_free_page(GFP_KERNEL);520	if (!buf) {521		pr_err("Unable to allocate FILEIO prot buf\n");522		return -ENOMEM;523	}524 525	rc = fd_do_prot_fill(cmd->se_dev, lba, nolb, buf, PAGE_SIZE);526 527	free_page((unsigned long)buf);528 529	return rc;530}531 532static sense_reason_t533fd_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb)534{535	struct file *file = FD_DEV(cmd->se_dev)->fd_file;536	struct inode *inode = file->f_mapping->host;537	int ret;538 539	if (!nolb) {540		return 0;541	}542 543	if (cmd->se_dev->dev_attrib.pi_prot_type) {544		ret = fd_do_prot_unmap(cmd, lba, nolb);545		if (ret)546			return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;547	}548 549	if (S_ISBLK(inode->i_mode)) {550		/* The backend is block device, use discard */551		struct block_device *bdev = I_BDEV(inode);552		struct se_device *dev = cmd->se_dev;553 554		ret = blkdev_issue_discard(bdev,555					   target_to_linux_sector(dev, lba),556					   target_to_linux_sector(dev,  nolb),557					   GFP_KERNEL);558		if (ret < 0) {559			pr_warn("FILEIO: blkdev_issue_discard() failed: %d\n",560				ret);561			return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;562		}563	} else {564		/* The backend is normal file, use fallocate */565		struct se_device *se_dev = cmd->se_dev;566		loff_t pos = lba * se_dev->dev_attrib.block_size;567		unsigned int len = nolb * se_dev->dev_attrib.block_size;568		int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE;569 570		if (!file->f_op->fallocate)571			return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;572 573		ret = file->f_op->fallocate(file, mode, pos, len);574		if (ret < 0) {575			pr_warn("FILEIO: fallocate() failed: %d\n", ret);576			return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;577		}578	}579 580	return 0;581}582 583static sense_reason_t584fd_execute_rw_buffered(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,585	      enum dma_data_direction data_direction)586{587	struct se_device *dev = cmd->se_dev;588	struct fd_dev *fd_dev = FD_DEV(dev);589	struct file *file = fd_dev->fd_file;590	struct file *pfile = fd_dev->fd_prot_file;591	sense_reason_t rc;592	int ret = 0;593	/*594	 * Call vectorized fileio functions to map struct scatterlist595	 * physical memory addresses to struct iovec virtual memory.596	 */597	if (data_direction == DMA_FROM_DEVICE) {598		if (cmd->prot_type && dev->dev_attrib.pi_prot_type) {599			ret = fd_do_rw(cmd, pfile, dev->prot_length,600				       cmd->t_prot_sg, cmd->t_prot_nents,601				       cmd->prot_length, 0);602			if (ret < 0)603				return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;604		}605 606		ret = fd_do_rw(cmd, file, dev->dev_attrib.block_size,607			       sgl, sgl_nents, cmd->data_length, 0);608 609		if (ret > 0 && cmd->prot_type && dev->dev_attrib.pi_prot_type &&610		    dev->dev_attrib.pi_prot_verify) {611			u32 sectors = cmd->data_length >>612					ilog2(dev->dev_attrib.block_size);613 614			rc = sbc_dif_verify(cmd, cmd->t_task_lba, sectors,615					    0, cmd->t_prot_sg, 0);616			if (rc)617				return rc;618		}619	} else {620		if (cmd->prot_type && dev->dev_attrib.pi_prot_type &&621		    dev->dev_attrib.pi_prot_verify) {622			u32 sectors = cmd->data_length >>623					ilog2(dev->dev_attrib.block_size);624 625			rc = sbc_dif_verify(cmd, cmd->t_task_lba, sectors,626					    0, cmd->t_prot_sg, 0);627			if (rc)628				return rc;629		}630 631		ret = fd_do_rw(cmd, file, dev->dev_attrib.block_size,632			       sgl, sgl_nents, cmd->data_length, 1);633		/*634		 * Perform implicit vfs_fsync_range() for fd_do_writev() ops635		 * for SCSI WRITEs with Forced Unit Access (FUA) set.636		 * Allow this to happen independent of WCE=0 setting.637		 */638		if (ret > 0 && (cmd->se_cmd_flags & SCF_FUA)) {639			loff_t start = cmd->t_task_lba *640				dev->dev_attrib.block_size;641			loff_t end;642 643			if (cmd->data_length)644				end = start + cmd->data_length - 1;645			else646				end = LLONG_MAX;647 648			vfs_fsync_range(fd_dev->fd_file, start, end, 1);649		}650 651		if (ret > 0 && cmd->prot_type && dev->dev_attrib.pi_prot_type) {652			ret = fd_do_rw(cmd, pfile, dev->prot_length,653				       cmd->t_prot_sg, cmd->t_prot_nents,654				       cmd->prot_length, 1);655			if (ret < 0)656				return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;657		}658	}659 660	if (ret < 0)661		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;662 663	target_complete_cmd(cmd, SAM_STAT_GOOD);664	return 0;665}666 667static sense_reason_t668fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,669	      enum dma_data_direction data_direction)670{671	struct se_device *dev = cmd->se_dev;672	struct fd_dev *fd_dev = FD_DEV(dev);673 674	/*675	 * We are currently limited by the number of iovecs (2048) per676	 * single vfs_[writev,readv] call.677	 */678	if (cmd->data_length > FD_MAX_BYTES) {679		pr_err("FILEIO: Not able to process I/O of %u bytes due to"680		       "FD_MAX_BYTES: %u iovec count limitation\n",681			cmd->data_length, FD_MAX_BYTES);682		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;683	}684 685	if (fd_dev->fbd_flags & FDBD_HAS_ASYNC_IO)686		return fd_execute_rw_aio(cmd, sgl, sgl_nents, data_direction);687	return fd_execute_rw_buffered(cmd, sgl, sgl_nents, data_direction);688}689 690enum {691	Opt_fd_dev_name, Opt_fd_dev_size, Opt_fd_buffered_io,692	Opt_fd_async_io, Opt_err693};694 695static match_table_t tokens = {696	{Opt_fd_dev_name, "fd_dev_name=%s"},697	{Opt_fd_dev_size, "fd_dev_size=%s"},698	{Opt_fd_buffered_io, "fd_buffered_io=%d"},699	{Opt_fd_async_io, "fd_async_io=%d"},700	{Opt_err, NULL}701};702 703static ssize_t fd_set_configfs_dev_params(struct se_device *dev,704		const char *page, ssize_t count)705{706	struct fd_dev *fd_dev = FD_DEV(dev);707	char *orig, *ptr, *arg_p, *opts;708	substring_t args[MAX_OPT_ARGS];709	int ret = 0, arg, token;710 711	opts = kstrdup(page, GFP_KERNEL);712	if (!opts)713		return -ENOMEM;714 715	orig = opts;716 717	while ((ptr = strsep(&opts, ",\n")) != NULL) {718		if (!*ptr)719			continue;720 721		token = match_token(ptr, tokens, args);722		switch (token) {723		case Opt_fd_dev_name:724			if (match_strlcpy(fd_dev->fd_dev_name, &args[0],725				FD_MAX_DEV_NAME) == 0) {726				ret = -EINVAL;727				break;728			}729			pr_debug("FILEIO: Referencing Path: %s\n",730					fd_dev->fd_dev_name);731			fd_dev->fbd_flags |= FBDF_HAS_PATH;732			break;733		case Opt_fd_dev_size:734			arg_p = match_strdup(&args[0]);735			if (!arg_p) {736				ret = -ENOMEM;737				break;738			}739			ret = kstrtoull(arg_p, 0, &fd_dev->fd_dev_size);740			kfree(arg_p);741			if (ret < 0) {742				pr_err("kstrtoull() failed for"743						" fd_dev_size=\n");744				goto out;745			}746			pr_debug("FILEIO: Referencing Size: %llu"747					" bytes\n", fd_dev->fd_dev_size);748			fd_dev->fbd_flags |= FBDF_HAS_SIZE;749			break;750		case Opt_fd_buffered_io:751			ret = match_int(args, &arg);752			if (ret)753				goto out;754			if (arg != 1) {755				pr_err("bogus fd_buffered_io=%d value\n", arg);756				ret = -EINVAL;757				goto out;758			}759 760			pr_debug("FILEIO: Using buffered I/O"761				" operations for struct fd_dev\n");762 763			fd_dev->fbd_flags |= FDBD_HAS_BUFFERED_IO_WCE;764			break;765		case Opt_fd_async_io:766			ret = match_int(args, &arg);767			if (ret)768				goto out;769			if (arg != 1) {770				pr_err("bogus fd_async_io=%d value\n", arg);771				ret = -EINVAL;772				goto out;773			}774 775			pr_debug("FILEIO: Using async I/O"776				" operations for struct fd_dev\n");777 778			fd_dev->fbd_flags |= FDBD_HAS_ASYNC_IO;779			break;780		default:781			break;782		}783	}784 785out:786	kfree(orig);787	return (!ret) ? count : ret;788}789 790static ssize_t fd_show_configfs_dev_params(struct se_device *dev, char *b)791{792	struct fd_dev *fd_dev = FD_DEV(dev);793	ssize_t bl = 0;794 795	bl = sprintf(b + bl, "TCM FILEIO ID: %u", fd_dev->fd_dev_id);796	bl += sprintf(b + bl, "        File: %s  Size: %llu  Mode: %s Async: %d\n",797		fd_dev->fd_dev_name, fd_dev->fd_dev_size,798		(fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) ?799		"Buffered-WCE" : "O_DSYNC",800		!!(fd_dev->fbd_flags & FDBD_HAS_ASYNC_IO));801	return bl;802}803 804static sector_t fd_get_blocks(struct se_device *dev)805{806	struct fd_dev *fd_dev = FD_DEV(dev);807	struct file *f = fd_dev->fd_file;808	struct inode *i = f->f_mapping->host;809	unsigned long long dev_size;810	/*811	 * When using a file that references an underlying struct block_device,812	 * ensure dev_size is always based on the current inode size in order813	 * to handle underlying block_device resize operations.814	 */815	if (S_ISBLK(i->i_mode))816		dev_size = i_size_read(i);817	else818		dev_size = fd_dev->fd_dev_size;819 820	return div_u64(dev_size - dev->dev_attrib.block_size,821		       dev->dev_attrib.block_size);822}823 824static int fd_init_prot(struct se_device *dev)825{826	struct fd_dev *fd_dev = FD_DEV(dev);827	struct file *prot_file, *file = fd_dev->fd_file;828	struct inode *inode;829	int ret, flags = O_RDWR | O_CREAT | O_LARGEFILE | O_DSYNC;830	char buf[FD_MAX_DEV_PROT_NAME];831 832	if (!file) {833		pr_err("Unable to locate fd_dev->fd_file\n");834		return -ENODEV;835	}836 837	inode = file->f_mapping->host;838	if (S_ISBLK(inode->i_mode)) {839		pr_err("FILEIO Protection emulation only supported on"840		       " !S_ISBLK\n");841		return -ENOSYS;842	}843 844	if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE)845		flags &= ~O_DSYNC;846 847	snprintf(buf, FD_MAX_DEV_PROT_NAME, "%s.protection",848		 fd_dev->fd_dev_name);849 850	prot_file = filp_open(buf, flags, 0600);851	if (IS_ERR(prot_file)) {852		pr_err("filp_open(%s) failed\n", buf);853		ret = PTR_ERR(prot_file);854		return ret;855	}856	fd_dev->fd_prot_file = prot_file;857 858	return 0;859}860 861static int fd_format_prot(struct se_device *dev)862{863	unsigned char *buf;864	int unit_size = FDBD_FORMAT_UNIT_SIZE * dev->dev_attrib.block_size;865	int ret;866 867	if (!dev->dev_attrib.pi_prot_type) {868		pr_err("Unable to format_prot while pi_prot_type == 0\n");869		return -ENODEV;870	}871 872	buf = vzalloc(unit_size);873	if (!buf) {874		pr_err("Unable to allocate FILEIO prot buf\n");875		return -ENOMEM;876	}877 878	pr_debug("Using FILEIO prot_length: %llu\n",879		 (unsigned long long)(dev->transport->get_blocks(dev) + 1) *880					dev->prot_length);881 882	ret = fd_do_prot_fill(dev, 0, dev->transport->get_blocks(dev) + 1,883			      buf, unit_size);884	vfree(buf);885	return ret;886}887 888static void fd_free_prot(struct se_device *dev)889{890	struct fd_dev *fd_dev = FD_DEV(dev);891 892	if (!fd_dev->fd_prot_file)893		return;894 895	filp_close(fd_dev->fd_prot_file, NULL);896	fd_dev->fd_prot_file = NULL;897}898 899static struct exec_cmd_ops fd_exec_cmd_ops = {900	.execute_rw		= fd_execute_rw,901	.execute_sync_cache	= fd_execute_sync_cache,902	.execute_write_same	= fd_execute_write_same,903	.execute_unmap		= fd_execute_unmap,904};905 906static sense_reason_t907fd_parse_cdb(struct se_cmd *cmd)908{909	return sbc_parse_cdb(cmd, &fd_exec_cmd_ops);910}911 912static const struct target_backend_ops fileio_ops = {913	.name			= "fileio",914	.inquiry_prod		= "FILEIO",915	.inquiry_rev		= FD_VERSION,916	.owner			= THIS_MODULE,917	.attach_hba		= fd_attach_hba,918	.detach_hba		= fd_detach_hba,919	.alloc_device		= fd_alloc_device,920	.configure_device	= fd_configure_device,921	.destroy_device		= fd_destroy_device,922	.free_device		= fd_free_device,923	.configure_unmap	= fd_configure_unmap,924	.parse_cdb		= fd_parse_cdb,925	.set_configfs_dev_params = fd_set_configfs_dev_params,926	.show_configfs_dev_params = fd_show_configfs_dev_params,927	.get_device_type	= sbc_get_device_type,928	.get_blocks		= fd_get_blocks,929	.init_prot		= fd_init_prot,930	.format_prot		= fd_format_prot,931	.free_prot		= fd_free_prot,932	.tb_dev_attrib_attrs	= sbc_attrib_attrs,933};934 935static int __init fileio_module_init(void)936{937	return transport_backend_register(&fileio_ops);938}939 940static void __exit fileio_module_exit(void)941{942	target_backend_unregister(&fileio_ops);943}944 945MODULE_DESCRIPTION("TCM FILEIO subsystem plugin");946MODULE_AUTHOR("nab@Linux-iSCSI.org");947MODULE_LICENSE("GPL");948 949module_init(fileio_module_init);950module_exit(fileio_module_exit);951