Orangefs: improve the POSIXness of interrupted writes...
authorMike Marshall <hubcap@omnibond.com>
Wed, 9 Mar 2016 18:12:37 +0000 (13:12 -0500)
committerMike Marshall <hubcap@omnibond.com>
Wed, 9 Mar 2016 18:12:37 +0000 (13:12 -0500)
Don't return EINTR on interrupted writes if some data has already
been written.

Signed-off-by: Mike Marshall <hubcap@omnibond.com>
fs/orangefs/file.c

index 6f2e0f745c5d484868b2a65d8dbbb76526437634..9b561b7894b383b14e2301541cb4da7fa717ecc7 100644 (file)
@@ -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;