Blame view
drivers/target/target_core_file.c
21.7 KB
c66ac9db8 [SCSI] target: Ad... |
1 2 3 4 5 |
/******************************************************************************* * Filename: target_core_file.c * * This file contains the Storage Engine <-> FILEIO transport specific functions * |
4c76251e8 target: Update co... |
6 |
* (c) Copyright 2005-2013 Datera, Inc. |
c66ac9db8 [SCSI] target: Ad... |
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
* * Nicholas A. Bellinger <nab@kernel.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ******************************************************************************/ |
c66ac9db8 [SCSI] target: Ad... |
25 26 27 28 29 30 |
#include <linux/string.h> #include <linux/parser.h> #include <linux/timer.h> #include <linux/blkdev.h> #include <linux/slab.h> #include <linux/spinlock.h> |
827509e38 drivers/target: A... |
31 |
#include <linux/module.h> |
5538d294d treewide: Add mis... |
32 |
#include <linux/vmalloc.h> |
70d3ae5c8 target/file: Add ... |
33 |
#include <linux/falloc.h> |
ba9299925 target: Minimize ... |
34 |
#include <scsi/scsi_proto.h> |
506427628 target/file: Add ... |
35 |
#include <asm/unaligned.h> |
c66ac9db8 [SCSI] target: Ad... |
36 37 |
#include <target/target_core_base.h> |
c4795fb20 target: header re... |
38 |
#include <target/target_core_backend.h> |
c66ac9db8 [SCSI] target: Ad... |
39 40 |
#include "target_core_file.h" |
0fd97ccf4 target: kill stru... |
41 42 43 44 |
static inline struct fd_dev *FD_DEV(struct se_device *dev) { return container_of(dev, struct fd_dev, dev); } |
c66ac9db8 [SCSI] target: Ad... |
45 |
|
c66ac9db8 [SCSI] target: Ad... |
46 47 48 49 50 |
static int fd_attach_hba(struct se_hba *hba, u32 host_id) { struct fd_host *fd_host; fd_host = kzalloc(sizeof(struct fd_host), GFP_KERNEL); |
6708bb27b target: Follow up... |
51 52 53 |
if (!fd_host) { pr_err("Unable to allocate memory for struct fd_host "); |
e3d6f909e target: Core clea... |
54 |
return -ENOMEM; |
c66ac9db8 [SCSI] target: Ad... |
55 56 57 |
} fd_host->fd_host_id = host_id; |
e3d6f909e target: Core clea... |
58 |
hba->hba_ptr = fd_host; |
c66ac9db8 [SCSI] target: Ad... |
59 |
|
6708bb27b target: Follow up... |
60 |
pr_debug("CORE_HBA[%d] - TCM FILEIO HBA Driver %s on Generic" |
c66ac9db8 [SCSI] target: Ad... |
61 62 |
" Target Core Stack %s ", hba->hba_id, FD_VERSION, |
ce8dd25d0 target: consolida... |
63 |
TARGET_CORE_VERSION); |
95cadace8 target/file: Upda... |
64 65 66 |
pr_debug("CORE_HBA[%d] - Attached FILEIO HBA: %u to Generic ", hba->hba_id, fd_host->fd_host_id); |
c66ac9db8 [SCSI] target: Ad... |
67 68 69 70 71 72 73 |
return 0; } static void fd_detach_hba(struct se_hba *hba) { struct fd_host *fd_host = hba->hba_ptr; |
6708bb27b target: Follow up... |
74 |
pr_debug("CORE_HBA[%d] - Detached FILEIO HBA: %u from Generic" |
c66ac9db8 [SCSI] target: Ad... |
75 76 77 78 79 80 |
" Target Core ", hba->hba_id, fd_host->fd_host_id); kfree(fd_host); hba->hba_ptr = NULL; } |
0fd97ccf4 target: kill stru... |
81 |
static struct se_device *fd_alloc_device(struct se_hba *hba, const char *name) |
c66ac9db8 [SCSI] target: Ad... |
82 83 |
{ struct fd_dev *fd_dev; |
8359cf43b target: remove us... |
84 |
struct fd_host *fd_host = hba->hba_ptr; |
c66ac9db8 [SCSI] target: Ad... |
85 86 |
fd_dev = kzalloc(sizeof(struct fd_dev), GFP_KERNEL); |
6708bb27b target: Follow up... |
87 88 89 |
if (!fd_dev) { pr_err("Unable to allocate memory for struct fd_dev "); |
c66ac9db8 [SCSI] target: Ad... |
90 91 92 93 |
return NULL; } fd_dev->fd_host = fd_host; |
6708bb27b target: Follow up... |
94 95 |
pr_debug("FILEIO: Allocated fd_dev for %p ", name); |
c66ac9db8 [SCSI] target: Ad... |
96 |
|
0fd97ccf4 target: kill stru... |
97 |
return &fd_dev->dev; |
c66ac9db8 [SCSI] target: Ad... |
98 |
} |
0fd97ccf4 target: kill stru... |
99 |
static int fd_configure_device(struct se_device *dev) |
c66ac9db8 [SCSI] target: Ad... |
100 |
{ |
0fd97ccf4 target: kill stru... |
101 102 |
struct fd_dev *fd_dev = FD_DEV(dev); struct fd_host *fd_host = dev->se_hba->hba_ptr; |
c66ac9db8 [SCSI] target: Ad... |
103 104 |
struct file *file; struct inode *inode = NULL; |
0fd97ccf4 target: kill stru... |
105 |
int flags, ret = -EINVAL; |
c66ac9db8 [SCSI] target: Ad... |
106 |
|
0fd97ccf4 target: kill stru... |
107 108 109 110 111 |
if (!(fd_dev->fbd_flags & FBDF_HAS_PATH)) { pr_err("Missing fd_dev_name= "); return -EINVAL; } |
c66ac9db8 [SCSI] target: Ad... |
112 |
|
c66ac9db8 [SCSI] target: Ad... |
113 |
/* |
a4dff3043 target/file: Use ... |
114 115 |
* Use O_DSYNC by default instead of O_SYNC to forgo syncing * of pure timestamp updates. |
c66ac9db8 [SCSI] target: Ad... |
116 |
*/ |
a4dff3043 target/file: Use ... |
117 |
flags = O_RDWR | O_CREAT | O_LARGEFILE | O_DSYNC; |
0fd97ccf4 target: kill stru... |
118 |
|
b32f4c7ed target/file: Re-e... |
119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
/* * Optionally allow fd_buffered_io=1 to be enabled for people * who want use the fs buffer cache as an WriteCache mechanism. * * This means that in event of a hard failure, there is a risk * of silent data-loss if the SCSI client has *not* performed a * forced unit access (FUA) write, or issued SYNCHRONIZE_CACHE * to write-out the entire device cache. */ if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) { pr_debug("FILEIO: Disabling O_DSYNC, using buffered FILEIO "); flags &= ~O_DSYNC; } |
c66ac9db8 [SCSI] target: Ad... |
133 |
|
dbc6e0222 delousing target_... |
134 |
file = filp_open(fd_dev->fd_dev_name, flags, 0600); |
613640e4e [SCSI] target: Co... |
135 |
if (IS_ERR(file)) { |
dbc6e0222 delousing target_... |
136 137 |
pr_err("filp_open(%s) failed ", fd_dev->fd_dev_name); |
613640e4e [SCSI] target: Co... |
138 139 140 |
ret = PTR_ERR(file); goto fail; } |
c66ac9db8 [SCSI] target: Ad... |
141 142 143 144 145 146 147 148 149 |
fd_dev->fd_file = file; /* * If using a block backend with this struct file, we extract * fd_dev->fd_[block,dev]_size from struct block_device. * * Otherwise, we use the passed fd_size= from configfs */ inode = file->f_mapping->host; if (S_ISBLK(inode->i_mode)) { |
0fd97ccf4 target: kill stru... |
150 |
struct request_queue *q = bdev_get_queue(inode->i_bdev); |
cd9323fd6 target: Fix bug i... |
151 |
unsigned long long dev_size; |
0fd97ccf4 target: kill stru... |
152 |
|
21363ca87 target/file: Fix ... |
153 |
fd_dev->fd_block_size = bdev_logical_block_size(inode->i_bdev); |
c66ac9db8 [SCSI] target: Ad... |
154 155 156 157 |
/* * Determine the number of bytes from i_size_read() minus * one (1) logical sector from underlying struct block_device */ |
cd9323fd6 target: Fix bug i... |
158 |
dev_size = (i_size_read(file->f_mapping->host) - |
c66ac9db8 [SCSI] target: Ad... |
159 |
fd_dev->fd_block_size); |
6708bb27b target: Follow up... |
160 |
pr_debug("FILEIO: Using size: %llu bytes from struct" |
c66ac9db8 [SCSI] target: Ad... |
161 162 |
" block_device blocks: %llu logical_block_size: %d ", |
cd9323fd6 target: Fix bug i... |
163 |
dev_size, div_u64(dev_size, fd_dev->fd_block_size), |
c66ac9db8 [SCSI] target: Ad... |
164 |
fd_dev->fd_block_size); |
8a9ebe717 target: Fix WRITE... |
165 |
|
ea263c7fa target: Fix max_u... |
166 |
if (target_configure_unmap_from_queue(&dev->dev_attrib, q)) |
70d3ae5c8 target/file: Add ... |
167 |
pr_debug("IFILE: BLOCK Discard support available," |
8a9ebe717 target: Fix WRITE... |
168 169 |
" disabled by default "); |
70d3ae5c8 target/file: Add ... |
170 171 172 173 174 |
/* * Enable write same emulation for IBLOCK and use 0xFFFF as * the smaller WRITE_SAME(10) only has a two-byte block count. */ dev->dev_attrib.max_write_same_len = 0xFFFF; |
0463a3fef target/file: Set ... |
175 176 177 |
if (blk_queue_nonrot(q)) dev->dev_attrib.is_nonrot = 1; |
c66ac9db8 [SCSI] target: Ad... |
178 179 |
} else { if (!(fd_dev->fbd_flags & FBDF_HAS_SIZE)) { |
6708bb27b target: Follow up... |
180 |
pr_err("FILEIO: Missing fd_dev_size=" |
c66ac9db8 [SCSI] target: Ad... |
181 182 183 184 185 |
" parameter, and no backing struct" " block_device "); goto fail; } |
21363ca87 target/file: Fix ... |
186 |
fd_dev->fd_block_size = FD_BLOCKSIZE; |
70d3ae5c8 target/file: Add ... |
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
/* * Limit UNMAP emulation to 8k Number of LBAs (NoLB) */ dev->dev_attrib.max_unmap_lba_count = 0x2000; /* * Currently hardcoded to 1 in Linux/SCSI code.. */ dev->dev_attrib.max_unmap_block_desc_count = 1; dev->dev_attrib.unmap_granularity = 1; dev->dev_attrib.unmap_granularity_alignment = 0; /* * Limit WRITE_SAME w/ UNMAP=0 emulation to 8k Number of LBAs (NoLB) * based upon struct iovec limit for vfs_writev() */ dev->dev_attrib.max_write_same_len = 0x1000; |
c66ac9db8 [SCSI] target: Ad... |
203 |
} |
21363ca87 target/file: Fix ... |
204 |
dev->dev_attrib.hw_block_size = fd_dev->fd_block_size; |
95cadace8 target/file: Upda... |
205 206 |
dev->dev_attrib.max_bytes_per_io = FD_MAX_BYTES; dev->dev_attrib.hw_max_sectors = FD_MAX_BYTES / fd_dev->fd_block_size; |
0fd97ccf4 target: kill stru... |
207 |
dev->dev_attrib.hw_queue_depth = FD_MAX_DEVICE_QUEUE_DEPTH; |
c66ac9db8 [SCSI] target: Ad... |
208 |
|
b32f4c7ed target/file: Re-e... |
209 210 211 212 |
if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) { pr_debug("FILEIO: Forcing setting of emulate_write_cache=1" " with FDBD_HAS_BUFFERED_IO_WCE "); |
0fd97ccf4 target: kill stru... |
213 |
dev->dev_attrib.emulate_write_cache = 1; |
b32f4c7ed target/file: Re-e... |
214 |
} |
c66ac9db8 [SCSI] target: Ad... |
215 216 |
fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++; fd_dev->fd_queue_depth = dev->queue_depth; |
6708bb27b target: Follow up... |
217 |
pr_debug("CORE_FILE[%u] - Added TCM FILEIO Device ID: %u at %s," |
c66ac9db8 [SCSI] target: Ad... |
218 219 220 |
" %llu total bytes ", fd_host->fd_host_id, fd_dev->fd_dev_id, fd_dev->fd_dev_name, fd_dev->fd_dev_size); |
0fd97ccf4 target: kill stru... |
221 |
return 0; |
c66ac9db8 [SCSI] target: Ad... |
222 223 224 225 226 |
fail: if (fd_dev->fd_file) { filp_close(fd_dev->fd_file, NULL); fd_dev->fd_file = NULL; } |
0fd97ccf4 target: kill stru... |
227 |
return ret; |
c66ac9db8 [SCSI] target: Ad... |
228 |
} |
4cc987eaf target: Drop lun_... |
229 |
static void fd_dev_call_rcu(struct rcu_head *p) |
c66ac9db8 [SCSI] target: Ad... |
230 |
{ |
4cc987eaf target: Drop lun_... |
231 |
struct se_device *dev = container_of(p, struct se_device, rcu_head); |
0fd97ccf4 target: kill stru... |
232 |
struct fd_dev *fd_dev = FD_DEV(dev); |
c66ac9db8 [SCSI] target: Ad... |
233 |
|
c66ac9db8 [SCSI] target: Ad... |
234 235 |
kfree(fd_dev); } |
0fd97ccf4 target: kill stru... |
236 |
static void fd_free_device(struct se_device *dev) |
42201b557 target/file: Add ... |
237 |
{ |
0fd97ccf4 target: kill stru... |
238 |
struct fd_dev *fd_dev = FD_DEV(dev); |
42201b557 target/file: Add ... |
239 |
|
c66ac9db8 [SCSI] target: Ad... |
240 241 242 |
if (fd_dev->fd_file) { filp_close(fd_dev->fd_file, NULL); fd_dev->fd_file = NULL; |
42201b557 target/file: Add ... |
243 |
} |
4cc987eaf target: Drop lun_... |
244 |
call_rcu(&dev->rcu_head, fd_dev_call_rcu); |
42201b557 target/file: Add ... |
245 |
} |
8287fa5fb target/file: Remo... |
246 247 248 |
static int fd_do_rw(struct se_cmd *cmd, struct file *fd, u32 block_size, struct scatterlist *sgl, u32 sgl_nents, u32 data_length, int is_write) |
c66ac9db8 [SCSI] target: Ad... |
249 |
{ |
5787cacd0 target: remove st... |
250 |
struct scatterlist *sg; |
6b9a44d09 target: use vfs_i... |
251 252 253 |
struct iov_iter iter; struct bio_vec *bvec; ssize_t len = 0; |
8287fa5fb target/file: Remo... |
254 |
loff_t pos = (cmd->t_task_lba * block_size); |
c66ac9db8 [SCSI] target: Ad... |
255 |
int ret = 0, i; |
6b9a44d09 target: use vfs_i... |
256 257 |
bvec = kcalloc(sgl_nents, sizeof(struct bio_vec), GFP_KERNEL); if (!bvec) { |
6708bb27b target: Follow up... |
258 259 |
pr_err("Unable to allocate fd_do_readv iov[] "); |
e3d6f909e target: Core clea... |
260 |
return -ENOMEM; |
c66ac9db8 [SCSI] target: Ad... |
261 |
} |
5787cacd0 target: remove st... |
262 |
for_each_sg(sgl, sg, sgl_nents, i) { |
6b9a44d09 target: use vfs_i... |
263 264 265 |
bvec[i].bv_page = sg_page(sg); bvec[i].bv_len = sg->length; bvec[i].bv_offset = sg->offset; |
c66ac9db8 [SCSI] target: Ad... |
266 |
|
6b9a44d09 target: use vfs_i... |
267 268 |
len += sg->length; } |
778229af9 target/file: merg... |
269 |
|
6b9a44d09 target: use vfs_i... |
270 |
iov_iter_bvec(&iter, ITER_BVEC, bvec, sgl_nents, len); |
778229af9 target/file: merg... |
271 |
if (is_write) |
6b9a44d09 target: use vfs_i... |
272 |
ret = vfs_iter_write(fd, &iter, &pos); |
778229af9 target/file: merg... |
273 |
else |
6b9a44d09 target: use vfs_i... |
274 |
ret = vfs_iter_read(fd, &iter, &pos); |
778229af9 target/file: merg... |
275 |
|
6b9a44d09 target: use vfs_i... |
276 |
kfree(bvec); |
778229af9 target/file: merg... |
277 278 |
if (is_write) { |
8287fa5fb target/file: Remo... |
279 |
if (ret < 0 || ret != data_length) { |
778229af9 target/file: merg... |
280 281 |
pr_err("%s() write returned %d ", __func__, ret); |
e3d6f909e target: Core clea... |
282 |
return (ret < 0 ? ret : -EINVAL); |
c66ac9db8 [SCSI] target: Ad... |
283 284 |
} } else { |
778229af9 target/file: merg... |
285 286 287 288 289 |
/* * Return zeros and GOOD status even if the READ did not return * the expected virt_size for struct file w/o a backing struct * block_device. */ |
496ad9aa8 new helper: file_... |
290 |
if (S_ISBLK(file_inode(fd)->i_mode)) { |
8287fa5fb target/file: Remo... |
291 |
if (ret < 0 || ret != data_length) { |
778229af9 target/file: merg... |
292 293 294 |
pr_err("%s() returned %d, expecting %u for " "S_ISBLK ", __func__, ret, |
8287fa5fb target/file: Remo... |
295 |
data_length); |
778229af9 target/file: merg... |
296 297 298 299 300 301 302 303 304 |
return (ret < 0 ? ret : -EINVAL); } } else { if (ret < 0) { pr_err("%s() returned %d for non S_ISBLK ", __func__, ret); return ret; } |
c66ac9db8 [SCSI] target: Ad... |
305 306 |
} } |
c66ac9db8 [SCSI] target: Ad... |
307 308 |
return 1; } |
de103c93a target: pass sens... |
309 310 |
static sense_reason_t fd_execute_sync_cache(struct se_cmd *cmd) |
c66ac9db8 [SCSI] target: Ad... |
311 |
{ |
c66ac9db8 [SCSI] target: Ad... |
312 |
struct se_device *dev = cmd->se_dev; |
0fd97ccf4 target: kill stru... |
313 |
struct fd_dev *fd_dev = FD_DEV(dev); |
a1d8b49ab target: Updates f... |
314 |
int immed = (cmd->t_task_cdb[1] & 0x2); |
c66ac9db8 [SCSI] target: Ad... |
315 316 317 318 319 320 321 322 |
loff_t start, end; int ret; /* * If the Immediate bit is set, queue up the GOOD response * for this SYNCHRONIZE_CACHE op */ if (immed) |
5787cacd0 target: remove st... |
323 |
target_complete_cmd(cmd, SAM_STAT_GOOD); |
c66ac9db8 [SCSI] target: Ad... |
324 325 326 327 |
/* * Determine if we will be flushing the entire device. */ |
a1d8b49ab target: Updates f... |
328 |
if (cmd->t_task_lba == 0 && cmd->data_length == 0) { |
c66ac9db8 [SCSI] target: Ad... |
329 330 331 |
start = 0; end = LLONG_MAX; } else { |
0fd97ccf4 target: kill stru... |
332 |
start = cmd->t_task_lba * dev->dev_attrib.block_size; |
c66ac9db8 [SCSI] target: Ad... |
333 |
if (cmd->data_length) |
62d3ab49b target/file: fix ... |
334 |
end = start + cmd->data_length - 1; |
c66ac9db8 [SCSI] target: Ad... |
335 336 337 338 339 340 |
else end = LLONG_MAX; } ret = vfs_fsync_range(fd_dev->fd_file, start, end, 1); if (ret != 0) |
6708bb27b target: Follow up... |
341 342 |
pr_err("FILEIO: vfs_fsync_range() failed: %d ", ret); |
c66ac9db8 [SCSI] target: Ad... |
343 |
|
5787cacd0 target: remove st... |
344 |
if (immed) |
ad67f0d9e target: move sync... |
345 |
return 0; |
5787cacd0 target: remove st... |
346 |
|
de103c93a target: pass sens... |
347 |
if (ret) |
5787cacd0 target: remove st... |
348 |
target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION); |
de103c93a target: pass sens... |
349 |
else |
5787cacd0 target: remove st... |
350 |
target_complete_cmd(cmd, SAM_STAT_GOOD); |
ad67f0d9e target: move sync... |
351 352 |
return 0; |
c66ac9db8 [SCSI] target: Ad... |
353 |
} |
7b745c84a target/file: Add ... |
354 355 356 357 358 |
static sense_reason_t fd_execute_write_same(struct se_cmd *cmd) { struct se_device *se_dev = cmd->se_dev; struct fd_dev *fd_dev = FD_DEV(se_dev); |
7b745c84a target/file: Add ... |
359 |
loff_t pos = cmd->t_task_lba * se_dev->dev_attrib.block_size; |
d4c5dcacf target: rewrite f... |
360 361 362 363 364 |
sector_t nolb = sbc_get_write_same_sectors(cmd); struct iov_iter iter; struct bio_vec *bvec; unsigned int len = 0, i; ssize_t ret; |
7b745c84a target/file: Add ... |
365 366 367 368 369 |
if (!nolb) { target_complete_cmd(cmd, SAM_STAT_GOOD); return 0; } |
afd73f1b6 target: Perform P... |
370 371 372 373 374 375 |
if (cmd->prot_op) { pr_err("WRITE_SAME: Protection information with FILEIO" " backends not supported "); return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } |
7b745c84a target/file: Add ... |
376 377 |
if (cmd->t_data_nents > 1 || |
d4c5dcacf target: rewrite f... |
378 |
cmd->t_data_sg[0].length != cmd->se_dev->dev_attrib.block_size) { |
7b745c84a target/file: Add ... |
379 |
pr_err("WRITE_SAME: Illegal SGL t_data_nents: %u length: %u" |
d4c5dcacf target: rewrite f... |
380 381 382 383 |
" block_size: %u ", cmd->t_data_nents, cmd->t_data_sg[0].length, |
7b745c84a target/file: Add ... |
384 385 386 |
cmd->se_dev->dev_attrib.block_size); return TCM_INVALID_CDB_FIELD; } |
d4c5dcacf target: rewrite f... |
387 388 |
bvec = kcalloc(nolb, sizeof(struct bio_vec), GFP_KERNEL); if (!bvec) |
7b745c84a target/file: Add ... |
389 |
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
d4c5dcacf target: rewrite f... |
390 391 392 393 |
for (i = 0; i < nolb; i++) { bvec[i].bv_page = sg_page(&cmd->t_data_sg[0]); bvec[i].bv_len = cmd->t_data_sg[0].length; bvec[i].bv_offset = cmd->t_data_sg[0].offset; |
7b745c84a target/file: Add ... |
394 |
|
d4c5dcacf target: rewrite f... |
395 396 |
len += se_dev->dev_attrib.block_size; } |
7b745c84a target/file: Add ... |
397 |
|
d4c5dcacf target: rewrite f... |
398 399 |
iov_iter_bvec(&iter, ITER_BVEC, bvec, nolb, len); ret = vfs_iter_write(fd_dev->fd_file, &iter, &pos); |
7b745c84a target/file: Add ... |
400 |
|
d4c5dcacf target: rewrite f... |
401 402 403 404 |
kfree(bvec); if (ret < 0 || ret != len) { pr_err("vfs_iter_write() returned %zd for write same ", ret); |
7b745c84a target/file: Add ... |
405 406 407 408 409 410 |
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } target_complete_cmd(cmd, SAM_STAT_GOOD); return 0; } |
64d240b72 target/file: Fix ... |
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 |
static int fd_do_prot_fill(struct se_device *se_dev, sector_t lba, sector_t nolb, void *buf, size_t bufsize) { struct fd_dev *fd_dev = FD_DEV(se_dev); struct file *prot_fd = fd_dev->fd_prot_file; sector_t prot_length, prot; loff_t pos = lba * se_dev->prot_length; if (!prot_fd) { pr_err("Unable to locate fd_dev->fd_prot_file "); return -ENODEV; } prot_length = nolb * se_dev->prot_length; for (prot = 0; prot < prot_length;) { sector_t len = min_t(sector_t, bufsize, prot_length - prot); ssize_t ret = kernel_write(prot_fd, buf, len, pos + prot); if (ret != len) { pr_err("vfs_write to prot file failed: %zd ", ret); return ret < 0 ? ret : -ENODEV; } prot += ret; } return 0; } static int fd_do_prot_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb) { void *buf; int rc; buf = (void *)__get_free_page(GFP_KERNEL); if (!buf) { pr_err("Unable to allocate FILEIO prot buf "); return -ENOMEM; } memset(buf, 0xff, PAGE_SIZE); rc = fd_do_prot_fill(cmd->se_dev, lba, nolb, buf, PAGE_SIZE); free_page((unsigned long)buf); return rc; } |
de103c93a target: pass sens... |
463 |
static sense_reason_t |
62e469425 target: simplify ... |
464 |
fd_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb) |
70d3ae5c8 target/file: Add ... |
465 |
{ |
62e469425 target: simplify ... |
466 |
struct file *file = FD_DEV(cmd->se_dev)->fd_file; |
70d3ae5c8 target/file: Add ... |
467 |
struct inode *inode = file->f_mapping->host; |
70d3ae5c8 target/file: Add ... |
468 |
int ret; |
64d240b72 target/file: Fix ... |
469 470 471 472 473 |
if (cmd->se_dev->dev_attrib.pi_prot_type) { ret = fd_do_prot_unmap(cmd, lba, nolb); if (ret) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } |
70d3ae5c8 target/file: Add ... |
474 475 476 |
if (S_ISBLK(inode->i_mode)) { /* The backend is block device, use discard */ struct block_device *bdev = inode->i_bdev; |
8a9ebe717 target: Fix WRITE... |
477 |
struct se_device *dev = cmd->se_dev; |
70d3ae5c8 target/file: Add ... |
478 |
|
8a9ebe717 target: Fix WRITE... |
479 480 481 482 |
ret = blkdev_issue_discard(bdev, target_to_linux_sector(dev, lba), target_to_linux_sector(dev, nolb), GFP_KERNEL, 0); |
70d3ae5c8 target/file: Add ... |
483 484 485 486 487 488 489 490 |
if (ret < 0) { pr_warn("FILEIO: blkdev_issue_discard() failed: %d ", ret); return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } } else { /* The backend is normal file, use fallocate */ |
43f55bbb1 target/file: Add ... |
491 492 |
struct se_device *se_dev = cmd->se_dev; loff_t pos = lba * se_dev->dev_attrib.block_size; |
70d3ae5c8 target/file: Add ... |
493 494 495 496 497 498 499 500 501 502 503 504 505 |
unsigned int len = nolb * se_dev->dev_attrib.block_size; int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE; if (!file->f_op->fallocate) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; ret = file->f_op->fallocate(file, mode, pos, len); if (ret < 0) { pr_warn("FILEIO: fallocate() failed: %d ", ret); return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } } |
43f55bbb1 target/file: Add ... |
506 507 508 509 |
return 0; } static sense_reason_t |
a82a9538d target: Allow sbc... |
510 511 |
fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, enum dma_data_direction data_direction) |
c66ac9db8 [SCSI] target: Ad... |
512 |
{ |
c66ac9db8 [SCSI] target: Ad... |
513 |
struct se_device *dev = cmd->se_dev; |
8287fa5fb target/file: Remo... |
514 515 516 |
struct fd_dev *fd_dev = FD_DEV(dev); struct file *file = fd_dev->fd_file; struct file *pfile = fd_dev->fd_prot_file; |
42201b557 target/file: Add ... |
517 |
sense_reason_t rc; |
c66ac9db8 [SCSI] target: Ad... |
518 |
int ret = 0; |
046ba6428 target: Drop arbi... |
519 520 521 522 523 524 |
/* * We are currently limited by the number of iovecs (2048) per * single vfs_[writev,readv] call. */ if (cmd->data_length > FD_MAX_BYTES) { pr_err("FILEIO: Not able to process I/O of %u bytes due to" |
291e3e51a target: fix spell... |
525 526 |
"FD_MAX_BYTES: %u iovec count limitation ", |
046ba6428 target: Drop arbi... |
527 528 529 |
cmd->data_length, FD_MAX_BYTES); return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } |
c66ac9db8 [SCSI] target: Ad... |
530 531 532 533 |
/* * Call vectorized fileio functions to map struct scatterlist * physical memory addresses to struct iovec virtual memory. */ |
5787cacd0 target: remove st... |
534 |
if (data_direction == DMA_FROM_DEVICE) { |
ee920469d target/file: Add ... |
535 |
if (cmd->prot_type && dev->dev_attrib.pi_prot_type) { |
8287fa5fb target/file: Remo... |
536 537 538 |
ret = fd_do_rw(cmd, pfile, dev->prot_length, cmd->t_prot_sg, cmd->t_prot_nents, cmd->prot_length, 0); |
42201b557 target/file: Add ... |
539 540 541 |
if (ret < 0) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } |
8287fa5fb target/file: Remo... |
542 543 |
ret = fd_do_rw(cmd, file, dev->dev_attrib.block_size, sgl, sgl_nents, cmd->data_length, 0); |
42201b557 target/file: Add ... |
544 |
|
ee920469d target/file: Add ... |
545 |
if (ret > 0 && cmd->prot_type && dev->dev_attrib.pi_prot_type) { |
8287fa5fb target/file: Remo... |
546 547 |
u32 sectors = cmd->data_length >> ilog2(dev->dev_attrib.block_size); |
42201b557 target/file: Add ... |
548 |
|
f75b6fae1 target: Merge sbc... |
549 |
rc = sbc_dif_verify(cmd, cmd->t_task_lba, sectors, |
8287fa5fb target/file: Remo... |
550 551 |
0, cmd->t_prot_sg, 0); if (rc) |
42201b557 target/file: Add ... |
552 |
return rc; |
42201b557 target/file: Add ... |
553 |
} |
c66ac9db8 [SCSI] target: Ad... |
554 |
} else { |
ee920469d target/file: Add ... |
555 |
if (cmd->prot_type && dev->dev_attrib.pi_prot_type) { |
8287fa5fb target/file: Remo... |
556 557 |
u32 sectors = cmd->data_length >> ilog2(dev->dev_attrib.block_size); |
42201b557 target/file: Add ... |
558 |
|
f75b6fae1 target: Merge sbc... |
559 560 |
rc = sbc_dif_verify(cmd, cmd->t_task_lba, sectors, 0, cmd->t_prot_sg, 0); |
8287fa5fb target/file: Remo... |
561 |
if (rc) |
42201b557 target/file: Add ... |
562 |
return rc; |
42201b557 target/file: Add ... |
563 |
} |
8287fa5fb target/file: Remo... |
564 565 |
ret = fd_do_rw(cmd, file, dev->dev_attrib.block_size, sgl, sgl_nents, cmd->data_length, 1); |
a4dff3043 target/file: Use ... |
566 |
/* |
125d0119d target core: rena... |
567 |
* Perform implicit vfs_fsync_range() for fd_do_writev() ops |
a4dff3043 target/file: Use ... |
568 569 570 |
* for SCSI WRITEs with Forced Unit Access (FUA) set. * Allow this to happen independent of WCE=0 setting. */ |
814e5b451 target: fix DPO a... |
571 |
if (ret > 0 && (cmd->se_cmd_flags & SCF_FUA)) { |
a4dff3043 target/file: Use ... |
572 |
loff_t start = cmd->t_task_lba * |
0fd97ccf4 target: kill stru... |
573 |
dev->dev_attrib.block_size; |
62d3ab49b target/file: fix ... |
574 575 576 577 578 579 |
loff_t end; if (cmd->data_length) end = start + cmd->data_length - 1; else end = LLONG_MAX; |
c66ac9db8 [SCSI] target: Ad... |
580 |
|
a4dff3043 target/file: Use ... |
581 582 |
vfs_fsync_range(fd_dev->fd_file, start, end, 1); } |
42201b557 target/file: Add ... |
583 |
|
ee920469d target/file: Add ... |
584 |
if (ret > 0 && cmd->prot_type && dev->dev_attrib.pi_prot_type) { |
8287fa5fb target/file: Remo... |
585 586 587 |
ret = fd_do_rw(cmd, pfile, dev->prot_length, cmd->t_prot_sg, cmd->t_prot_nents, cmd->prot_length, 1); |
42201b557 target/file: Add ... |
588 589 590 |
if (ret < 0) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } |
c66ac9db8 [SCSI] target: Ad... |
591 |
} |
8287fa5fb target/file: Remo... |
592 |
if (ret < 0) |
de103c93a target: pass sens... |
593 |
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
5787cacd0 target: remove st... |
594 595 |
if (ret) target_complete_cmd(cmd, SAM_STAT_GOOD); |
03e98c9eb target: Address l... |
596 |
return 0; |
c66ac9db8 [SCSI] target: Ad... |
597 |
} |
c66ac9db8 [SCSI] target: Ad... |
598 599 600 601 602 603 604 |
enum { Opt_fd_dev_name, Opt_fd_dev_size, Opt_fd_buffered_io, Opt_err }; static match_table_t tokens = { {Opt_fd_dev_name, "fd_dev_name=%s"}, {Opt_fd_dev_size, "fd_dev_size=%s"}, |
b32f4c7ed target/file: Re-e... |
605 |
{Opt_fd_buffered_io, "fd_buffered_io=%d"}, |
c66ac9db8 [SCSI] target: Ad... |
606 607 |
{Opt_err, NULL} }; |
0fd97ccf4 target: kill stru... |
608 609 |
static ssize_t fd_set_configfs_dev_params(struct se_device *dev, const char *page, ssize_t count) |
c66ac9db8 [SCSI] target: Ad... |
610 |
{ |
0fd97ccf4 target: kill stru... |
611 |
struct fd_dev *fd_dev = FD_DEV(dev); |
c66ac9db8 [SCSI] target: Ad... |
612 613 |
char *orig, *ptr, *arg_p, *opts; substring_t args[MAX_OPT_ARGS]; |
b32f4c7ed target/file: Re-e... |
614 |
int ret = 0, arg, token; |
c66ac9db8 [SCSI] target: Ad... |
615 616 617 618 619 620 |
opts = kstrdup(page, GFP_KERNEL); if (!opts) return -ENOMEM; orig = opts; |
90c161b64 target: use \n as... |
621 622 |
while ((ptr = strsep(&opts, ", ")) != NULL) { |
c66ac9db8 [SCSI] target: Ad... |
623 624 625 626 627 628 |
if (!*ptr) continue; token = match_token(ptr, tokens, args); switch (token) { case Opt_fd_dev_name: |
dbc6e0222 delousing target_... |
629 630 631 |
if (match_strlcpy(fd_dev->fd_dev_name, &args[0], FD_MAX_DEV_NAME) == 0) { ret = -EINVAL; |
6d1802539 [SCSI] target: Fi... |
632 633 |
break; } |
6708bb27b target: Follow up... |
634 635 |
pr_debug("FILEIO: Referencing Path: %s ", |
c66ac9db8 [SCSI] target: Ad... |
636 637 638 639 640 |
fd_dev->fd_dev_name); fd_dev->fbd_flags |= FBDF_HAS_PATH; break; case Opt_fd_dev_size: arg_p = match_strdup(&args[0]); |
6d1802539 [SCSI] target: Fi... |
641 642 643 644 |
if (!arg_p) { ret = -ENOMEM; break; } |
57103d7fe target: replace s... |
645 |
ret = kstrtoull(arg_p, 0, &fd_dev->fd_dev_size); |
6d1802539 [SCSI] target: Fi... |
646 |
kfree(arg_p); |
c66ac9db8 [SCSI] target: Ad... |
647 |
if (ret < 0) { |
57103d7fe target: replace s... |
648 |
pr_err("kstrtoull() failed for" |
c66ac9db8 [SCSI] target: Ad... |
649 650 651 652 |
" fd_dev_size= "); goto out; } |
6708bb27b target: Follow up... |
653 |
pr_debug("FILEIO: Referencing Size: %llu" |
c66ac9db8 [SCSI] target: Ad... |
654 655 656 657 |
" bytes ", fd_dev->fd_dev_size); fd_dev->fbd_flags |= FBDF_HAS_SIZE; break; |
b32f4c7ed target/file: Re-e... |
658 |
case Opt_fd_buffered_io: |
ce31c1b0d target: correctly... |
659 660 661 |
ret = match_int(args, &arg); if (ret) goto out; |
b32f4c7ed target/file: Re-e... |
662 663 664 665 666 667 668 669 670 671 672 673 674 |
if (arg != 1) { pr_err("bogus fd_buffered_io=%d value ", arg); ret = -EINVAL; goto out; } pr_debug("FILEIO: Using buffered I/O" " operations for struct fd_dev "); fd_dev->fbd_flags |= FDBD_HAS_BUFFERED_IO_WCE; break; |
c66ac9db8 [SCSI] target: Ad... |
675 676 677 678 679 680 681 682 683 |
default: break; } } out: kfree(orig); return (!ret) ? count : ret; } |
0fd97ccf4 target: kill stru... |
684 |
static ssize_t fd_show_configfs_dev_params(struct se_device *dev, char *b) |
c66ac9db8 [SCSI] target: Ad... |
685 |
{ |
0fd97ccf4 target: kill stru... |
686 |
struct fd_dev *fd_dev = FD_DEV(dev); |
c66ac9db8 [SCSI] target: Ad... |
687 688 689 |
ssize_t bl = 0; bl = sprintf(b + bl, "TCM FILEIO ID: %u", fd_dev->fd_dev_id); |
b32f4c7ed target/file: Re-e... |
690 691 692 693 694 |
bl += sprintf(b + bl, " File: %s Size: %llu Mode: %s ", fd_dev->fd_dev_name, fd_dev->fd_dev_size, (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) ? "Buffered-WCE" : "O_DSYNC"); |
c66ac9db8 [SCSI] target: Ad... |
695 696 |
return bl; } |
c66ac9db8 [SCSI] target: Ad... |
697 698 |
static sector_t fd_get_blocks(struct se_device *dev) { |
0fd97ccf4 target: kill stru... |
699 |
struct fd_dev *fd_dev = FD_DEV(dev); |
cd9323fd6 target: Fix bug i... |
700 701 702 703 704 705 706 707 708 |
struct file *f = fd_dev->fd_file; struct inode *i = f->f_mapping->host; unsigned long long dev_size; /* * When using a file that references an underlying struct block_device, * ensure dev_size is always based on the current inode size in order * to handle underlying block_device resize operations. */ if (S_ISBLK(i->i_mode)) |
21363ca87 target/file: Fix ... |
709 |
dev_size = i_size_read(i); |
cd9323fd6 target: Fix bug i... |
710 711 |
else dev_size = fd_dev->fd_dev_size; |
c66ac9db8 [SCSI] target: Ad... |
712 |
|
21363ca87 target/file: Fix ... |
713 714 |
return div_u64(dev_size - dev->dev_attrib.block_size, dev->dev_attrib.block_size); |
c66ac9db8 [SCSI] target: Ad... |
715 |
} |
0f5e2ec46 target/file: Add ... |
716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 |
static int fd_init_prot(struct se_device *dev) { struct fd_dev *fd_dev = FD_DEV(dev); struct file *prot_file, *file = fd_dev->fd_file; struct inode *inode; int ret, flags = O_RDWR | O_CREAT | O_LARGEFILE | O_DSYNC; char buf[FD_MAX_DEV_PROT_NAME]; if (!file) { pr_err("Unable to locate fd_dev->fd_file "); return -ENODEV; } inode = file->f_mapping->host; if (S_ISBLK(inode->i_mode)) { pr_err("FILEIO Protection emulation only supported on" " !S_ISBLK "); return -ENOSYS; } if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) flags &= ~O_DSYNC; snprintf(buf, FD_MAX_DEV_PROT_NAME, "%s.protection", fd_dev->fd_dev_name); prot_file = filp_open(buf, flags, 0600); if (IS_ERR(prot_file)) { pr_err("filp_open(%s) failed ", buf); ret = PTR_ERR(prot_file); return ret; } fd_dev->fd_prot_file = prot_file; return 0; } |
0f5e2ec46 target/file: Add ... |
755 756 |
static int fd_format_prot(struct se_device *dev) { |
0f5e2ec46 target/file: Add ... |
757 |
unsigned char *buf; |
0f5e2ec46 target/file: Add ... |
758 |
int unit_size = FDBD_FORMAT_UNIT_SIZE * dev->dev_attrib.block_size; |
64d240b72 target/file: Fix ... |
759 |
int ret; |
0f5e2ec46 target/file: Add ... |
760 761 762 763 764 765 |
if (!dev->dev_attrib.pi_prot_type) { pr_err("Unable to format_prot while pi_prot_type == 0 "); return -ENODEV; } |
0f5e2ec46 target/file: Add ... |
766 |
|
0f5e2ec46 target/file: Add ... |
767 768 769 770 771 772 |
buf = vzalloc(unit_size); if (!buf) { pr_err("Unable to allocate FILEIO prot buf "); return -ENOMEM; } |
0f5e2ec46 target/file: Add ... |
773 774 775 |
pr_debug("Using FILEIO prot_length: %llu ", |
64d240b72 target/file: Fix ... |
776 777 |
(unsigned long long)(dev->transport->get_blocks(dev) + 1) * dev->prot_length); |
0f5e2ec46 target/file: Add ... |
778 |
|
80dcd0c10 Target/file: plac... |
779 |
memset(buf, 0xff, unit_size); |
64d240b72 target/file: Fix ... |
780 781 |
ret = fd_do_prot_fill(dev, 0, dev->transport->get_blocks(dev) + 1, buf, unit_size); |
0f5e2ec46 target/file: Add ... |
782 783 784 785 786 787 788 789 790 791 792 793 794 795 |
vfree(buf); return ret; } static void fd_free_prot(struct se_device *dev) { struct fd_dev *fd_dev = FD_DEV(dev); if (!fd_dev->fd_prot_file) return; filp_close(fd_dev->fd_prot_file, NULL); fd_dev->fd_prot_file = NULL; } |
9e999a6c5 target: rename sp... |
796 |
static struct sbc_ops fd_sbc_ops = { |
0c2ad7d11 target: add struc... |
797 |
.execute_rw = fd_execute_rw, |
ad67f0d9e target: move sync... |
798 |
.execute_sync_cache = fd_execute_sync_cache, |
7b745c84a target/file: Add ... |
799 |
.execute_write_same = fd_execute_write_same, |
506427628 target/file: Add ... |
800 |
.execute_unmap = fd_execute_unmap, |
0c2ad7d11 target: add struc... |
801 |
}; |
de103c93a target: pass sens... |
802 803 |
static sense_reason_t fd_parse_cdb(struct se_cmd *cmd) |
0c2ad7d11 target: add struc... |
804 |
{ |
9e999a6c5 target: rename sp... |
805 |
return sbc_parse_cdb(cmd, &fd_sbc_ops); |
0c2ad7d11 target: add struc... |
806 |
} |
0a06d4309 target: simplify ... |
807 |
static const struct target_backend_ops fileio_ops = { |
c66ac9db8 [SCSI] target: Ad... |
808 |
.name = "fileio", |
0fd97ccf4 target: kill stru... |
809 810 |
.inquiry_prod = "FILEIO", .inquiry_rev = FD_VERSION, |
c66ac9db8 [SCSI] target: Ad... |
811 |
.owner = THIS_MODULE, |
c66ac9db8 [SCSI] target: Ad... |
812 813 |
.attach_hba = fd_attach_hba, .detach_hba = fd_detach_hba, |
0fd97ccf4 target: kill stru... |
814 815 |
.alloc_device = fd_alloc_device, .configure_device = fd_configure_device, |
c66ac9db8 [SCSI] target: Ad... |
816 |
.free_device = fd_free_device, |
0c2ad7d11 target: add struc... |
817 |
.parse_cdb = fd_parse_cdb, |
c66ac9db8 [SCSI] target: Ad... |
818 819 |
.set_configfs_dev_params = fd_set_configfs_dev_params, .show_configfs_dev_params = fd_show_configfs_dev_params, |
6f23ac8a3 target: provide g... |
820 |
.get_device_type = sbc_get_device_type, |
c66ac9db8 [SCSI] target: Ad... |
821 |
.get_blocks = fd_get_blocks, |
0f5e2ec46 target/file: Add ... |
822 823 824 |
.init_prot = fd_init_prot, .format_prot = fd_format_prot, .free_prot = fd_free_prot, |
5873c4d15 target: consolida... |
825 |
.tb_dev_attrib_attrs = sbc_attrib_attrs, |
c66ac9db8 [SCSI] target: Ad... |
826 827 828 829 |
}; static int __init fileio_module_init(void) { |
0a06d4309 target: simplify ... |
830 |
return transport_backend_register(&fileio_ops); |
c66ac9db8 [SCSI] target: Ad... |
831 |
} |
63b91d5a4 target: Add __exi... |
832 |
static void __exit fileio_module_exit(void) |
c66ac9db8 [SCSI] target: Ad... |
833 |
{ |
0a06d4309 target: simplify ... |
834 |
target_backend_unregister(&fileio_ops); |
c66ac9db8 [SCSI] target: Ad... |
835 836 837 838 839 840 841 842 |
} MODULE_DESCRIPTION("TCM FILEIO subsystem plugin"); MODULE_AUTHOR("nab@Linux-iSCSI.org"); MODULE_LICENSE("GPL"); module_init(fileio_module_init); module_exit(fileio_module_exit); |