Orangefs: improve the POSIXness of interrupted writes...

Don't return EINTR on interrupted writes if some data has already
been written.

Signed-off-by: Mike Marshall <hubcap@omnibond.com>
This commit is contained in:
Mike Marshall 2016-03-09 13:12:37 -05:00
parent cf07c0bf88
commit 162ada7764
1 changed files with 45 additions and 9 deletions

View File

@ -180,21 +180,57 @@ static ssize_t wait_for_direct_io(enum ORANGEFS_io_type type, struct inode *inod
}
if (ret < 0) {
/*
* don't write an error to syslog on signaled operation
* termination unless we've got debugging turned on, as
* this can happen regularly (i.e. ctrl-c)
*/
if (ret == -EINTR)
if (ret == -EINTR) {
/*
* We can't return EINTR if any data was written,
* it's not POSIX. It is minimally acceptable
* to give a partial write, the way NFS does.
*
* It would be optimal to return all or nothing,
* but if a userspace write is bigger than
* an IO buffer, and the interrupt occurs
* between buffer writes, that would not be
* possible.
*/
switch (new_op->op_state - OP_VFS_STATE_GIVEN_UP) {
/*
* If the op was waiting when the interrupt
* occurred, then the client-core did not
* trigger the write.
*/
case OP_VFS_STATE_WAITING:
if (*offset == 0)
ret = -EINTR;
else
ret = 0;
break;
/*
* If the op was in progress when the interrupt
* occurred, then the client-core was able to
* trigger the write.
*/
case OP_VFS_STATE_INPROGR:
ret = total_size;
break;
default:
gossip_err("%s: unexpected op state :%d:.\n",
__func__,
new_op->op_state);
ret = 0;
break;
}
gossip_debug(GOSSIP_FILE_DEBUG,
"%s: returning error %ld\n", __func__,
(long)ret);
else
"%s: got EINTR, state:%d: %p\n",
__func__,
new_op->op_state,
new_op);
} else {
gossip_err("%s: error in %s handle %pU, returning %zd\n",
__func__,
type == ORANGEFS_IO_READ ?
"read from" : "write to",
handle, ret);
}
if (orangefs_cancel_op_in_progress(new_op))
return ret;