target/file: Use O_DSYNC by default for FILEIO backends

Convert to use O_DSYNC for all cases at FILEIO backend creation time to
avoid the extra syncing of pure timestamp updates with legacy O_SYNC during
default operation as recommended by hch.  Continue to do this independently of
Write Cache Enable (WCE) bit, as WCE=0 is currently the default for all backend
devices and enabled by user on per device basis via attrib/emulate_write_cache.

This patch drops the now unnecessary fd_buffered_io= token usage that was
originally signalling when to explictly disable O_SYNC at backend creation
time for buffered I/O operation.  This can end up being dangerous for a number
of reasons during physical node failure, so go ahead and drop this option
for now when O_DSYNC is used as the default.

Also allow explict FUA WRITEs -> vfs_fsync_range() call to function in
fd_execute_cmd() independently of WCE bit setting.

Reported-by: Christoph Hellwig <hch@lst.de>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
This commit is contained in:
Nicholas Bellinger 2012-05-30 16:25:41 -07:00
parent 5f2a3d6191
commit a4dff3043c
2 changed files with 17 additions and 54 deletions

View file

@ -133,16 +133,11 @@ static struct se_device *fd_create_virtdevice(
ret = PTR_ERR(dev_p); ret = PTR_ERR(dev_p);
goto fail; goto fail;
} }
/* O_DIRECT too? */
flags = O_RDWR | O_CREAT | O_LARGEFILE;
/* /*
* If fd_buffered_io=1 has not been set explicitly (the default), * Use O_DSYNC by default instead of O_SYNC to forgo syncing
* use O_SYNC to force FILEIO writes to disk. * of pure timestamp updates.
*/ */
if (!(fd_dev->fbd_flags & FDBD_USE_BUFFERED_IO)) flags = O_RDWR | O_CREAT | O_LARGEFILE | O_DSYNC;
flags |= O_SYNC;
file = filp_open(dev_p, flags, 0600); file = filp_open(dev_p, flags, 0600);
if (IS_ERR(file)) { if (IS_ERR(file)) {
@ -380,23 +375,6 @@ static void fd_emulate_sync_cache(struct se_cmd *cmd)
} }
} }
static void fd_emulate_write_fua(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
struct fd_dev *fd_dev = dev->dev_ptr;
loff_t start = cmd->t_task_lba *
dev->se_sub_dev->se_dev_attrib.block_size;
loff_t end = start + cmd->data_length;
int ret;
pr_debug("FILEIO: FUA WRITE LBA: %llu, bytes: %u\n",
cmd->t_task_lba, cmd->data_length);
ret = vfs_fsync_range(fd_dev->fd_file, start, end, 1);
if (ret != 0)
pr_err("FILEIO: vfs_fsync_range() failed: %d\n", ret);
}
static int fd_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl, static int fd_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl,
u32 sgl_nents, enum dma_data_direction data_direction) u32 sgl_nents, enum dma_data_direction data_direction)
{ {
@ -411,19 +389,21 @@ static int fd_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl,
ret = fd_do_readv(cmd, sgl, sgl_nents); ret = fd_do_readv(cmd, sgl, sgl_nents);
} else { } else {
ret = fd_do_writev(cmd, sgl, sgl_nents); ret = fd_do_writev(cmd, sgl, sgl_nents);
/*
* Perform implict vfs_fsync_range() for fd_do_writev() ops
* for SCSI WRITEs with Forced Unit Access (FUA) set.
* Allow this to happen independent of WCE=0 setting.
*/
if (ret > 0 && if (ret > 0 &&
dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0 &&
dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0 && dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0 &&
(cmd->se_cmd_flags & SCF_FUA)) { (cmd->se_cmd_flags & SCF_FUA)) {
/* struct fd_dev *fd_dev = dev->dev_ptr;
* We might need to be a bit smarter here loff_t start = cmd->t_task_lba *
* and return some sense data to let the initiator dev->se_sub_dev->se_dev_attrib.block_size;
* know the FUA WRITE cache sync failed..? loff_t end = start + cmd->data_length;
*/
fd_emulate_write_fua(cmd);
}
vfs_fsync_range(fd_dev->fd_file, start, end, 1);
}
} }
if (ret < 0) { if (ret < 0) {
@ -442,7 +422,6 @@ enum {
static match_table_t tokens = { static match_table_t tokens = {
{Opt_fd_dev_name, "fd_dev_name=%s"}, {Opt_fd_dev_name, "fd_dev_name=%s"},
{Opt_fd_dev_size, "fd_dev_size=%s"}, {Opt_fd_dev_size, "fd_dev_size=%s"},
{Opt_fd_buffered_io, "fd_buffered_io=%d"},
{Opt_err, NULL} {Opt_err, NULL}
}; };
@ -454,7 +433,7 @@ static ssize_t fd_set_configfs_dev_params(
struct fd_dev *fd_dev = se_dev->se_dev_su_ptr; struct fd_dev *fd_dev = se_dev->se_dev_su_ptr;
char *orig, *ptr, *arg_p, *opts; char *orig, *ptr, *arg_p, *opts;
substring_t args[MAX_OPT_ARGS]; substring_t args[MAX_OPT_ARGS];
int ret = 0, arg, token; int ret = 0, token;
opts = kstrdup(page, GFP_KERNEL); opts = kstrdup(page, GFP_KERNEL);
if (!opts) if (!opts)
@ -498,19 +477,6 @@ static ssize_t fd_set_configfs_dev_params(
" bytes\n", fd_dev->fd_dev_size); " bytes\n", fd_dev->fd_dev_size);
fd_dev->fbd_flags |= FBDF_HAS_SIZE; fd_dev->fbd_flags |= FBDF_HAS_SIZE;
break; break;
case Opt_fd_buffered_io:
match_int(args, &arg);
if (arg != 1) {
pr_err("bogus fd_buffered_io=%d value\n", arg);
ret = -EINVAL;
goto out;
}
pr_debug("FILEIO: Using buffered I/O"
" operations for struct fd_dev\n");
fd_dev->fbd_flags |= FDBD_USE_BUFFERED_IO;
break;
default: default:
break; break;
} }
@ -542,10 +508,8 @@ static ssize_t fd_show_configfs_dev_params(
ssize_t bl = 0; ssize_t bl = 0;
bl = sprintf(b + bl, "TCM FILEIO ID: %u", fd_dev->fd_dev_id); bl = sprintf(b + bl, "TCM FILEIO ID: %u", fd_dev->fd_dev_id);
bl += sprintf(b + bl, " File: %s Size: %llu Mode: %s\n", bl += sprintf(b + bl, " File: %s Size: %llu Mode: O_DSYNC\n",
fd_dev->fd_dev_name, fd_dev->fd_dev_size, fd_dev->fd_dev_name, fd_dev->fd_dev_size);
(fd_dev->fbd_flags & FDBD_USE_BUFFERED_IO) ?
"Buffered" : "Synchronous");
return bl; return bl;
} }

View file

@ -14,7 +14,6 @@
#define FBDF_HAS_PATH 0x01 #define FBDF_HAS_PATH 0x01
#define FBDF_HAS_SIZE 0x02 #define FBDF_HAS_SIZE 0x02
#define FDBD_USE_BUFFERED_IO 0x04
struct fd_dev { struct fd_dev {
u32 fbd_flags; u32 fbd_flags;