diff options
author | Mike Marshall <hubcap@omnibond.com> | 2016-03-09 13:12:37 -0500 |
---|---|---|
committer | Mike Marshall <hubcap@omnibond.com> | 2016-03-09 13:12:37 -0500 |
commit | 162ada7764162eb2eb0a02546f820ca8b099cdea (patch) | |
tree | 6fc674756ae2646012bef5539ea6fdf7a088faa4 /fs/orangefs | |
parent | cf07c0bf88b7e8765361e808b61fef287caedfe3 (diff) | |
download | linux-next-162ada7764162eb2eb0a02546f820ca8b099cdea.tar.gz |
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')
-rw-r--r-- | fs/orangefs/file.c | 54 |
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; |