summaryrefslogtreecommitdiff
path: root/fs/orangefs/file.c
diff options
context:
space:
mode:
authorMike Marshall <hubcap@omnibond.com>2016-03-09 21:12:37 +0300
committerMike Marshall <hubcap@omnibond.com>2016-03-09 21:12:37 +0300
commit162ada7764162eb2eb0a02546f820ca8b099cdea (patch)
tree6fc674756ae2646012bef5539ea6fdf7a088faa4 /fs/orangefs/file.c
parentcf07c0bf88b7e8765361e808b61fef287caedfe3 (diff)
downloadlinux-162ada7764162eb2eb0a02546f820ca8b099cdea.tar.xz
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>
Diffstat (limited to 'fs/orangefs/file.c')
-rw-r--r--fs/orangefs/file.c54
1 files changed, 45 insertions, 9 deletions
diff --git a/fs/orangefs/file.c b/fs/orangefs/file.c
index 6f2e0f745c5d..9b561b7894b3 100644
--- a/fs/orangefs/file.c
+++ b/fs/orangefs/file.c
@@ -180,21 +180,57 @@ populate_shared_memory:
}
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;