]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
dtrace: provide a corrected implementation of the 'errno' D variable
authorKris Van Hees <kris.van.hees@oracle.com>
Thu, 31 Oct 2013 09:22:56 +0000 (05:22 -0400)
committerKris Van Hees <kris.van.hees@oracle.com>
Wed, 6 Nov 2013 21:40:33 +0000 (16:40 -0500)
This commit provides a corrected implementation for the 'errno' D variable.
It is defined as holding the error code (if non-zero) during the current
system call execution.  If the system call is successful, or if no system
call is being executed, its value is to be 0.  On (Open)Solaris, this was
retrieved from a task variable that is assigned an error code as soon as
an error is encountered during the processing of a system call, i.e. system
calls use a task variable to store any error code encountered during
execution, and this is used upon return from the system call to alert
userspace of the error code status of the system call.  In Linux, system
calls are implemented in the more regular fashion (for Linux at least)
of returning error codes as return values of functions, and therefore
there is no task level variable to consult.  So, instead we recognize that
at this point) 'errno' only has meaning during the processing of syscall
return probes, which are handled from the system call wrapper, after the
system call implementation has been executed.

It would therefore be sufficient and correct to assign the value of 'errno'
at that point, but that would require a task variable to be added to the
task struct in order for this value to be recorded.

In order to avoid adding a member to the task struct, we (ab)use the fact
that we can recognize whether we are executing a D action for a syscall
return probe, and if we are *and* if 'errno' is being retrieved, we look
at the arg0 value for the probe (which is defined as the return value of
the syscall), and if the value is between 0 and -2048, we return the error
code it represents as errno.

Orabug: 17704568

Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com>
Reviewed-by: Chuck Anderson <chuck.anderson@oracle.com>
dtrace/dtrace_dif.c

index d6339a8dc558d9618e128e2a2ec37d5a0b20aeb0..d39a0a61f63b14965298aaf43b27d6608d415740 100644 (file)
@@ -2301,15 +2301,43 @@ static uint64_t dtrace_dif_variable(dtrace_mstate_t *mstate,
                 */
                return (uint64_t)current->real_cred->gid;
 
-       case DIF_VAR_ERRNO:
+       case DIF_VAR_ERRNO: {
+               int64_t arg0;
+
+               ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE);
+
                if (!dtrace_priv_proc(state))
                        return 0;
 
                /*
-                * It is always safe to dereference current, it always points
-                * to a valid task_struct.
+                * We need to do some magic here to get the correct semantics
+                * for the 'errno' variable.  It can only have a non-zero value
+                * when executing a system call, and for Linux, only after the
+                * actual system call implementation has completed, indicating
+                * in its return value either an error code (-2048 < errno < 0)
+                * or a valid result.  So, the only time we can expect a valid
+                * value in errno is during the processing of any return probe
+                * in the syscall provider.  In all other cases, it should have
+                * the value 0.
+                *
+                * So, we only look at probes that match: syscall:::return
+                */
+               if (strncmp(mstate->dtms_probe->dtpr_provider->dtpv_name,
+                           "syscall", 7) != 0)
+                       return 0;
+               if (strncmp(mstate->dtms_probe->dtpr_name, "return", 6) != 0)
+                       return 0;
+
+               /*
+                * Error number is present if arg0 lies between 0 and -2048,
+                * exclusive.
                 */
-               return (uint64_t)current->thread.error_code;
+               arg0 = (int64_t)mstate->dtms_arg[ndx];
+               if (arg0 < 0 && arg0 > -2048)
+                       return (uint64_t)-arg0;
+
+               return 0;
+       }
 
        case DIF_VAR_CURCPU:
                return (uint64_t)(uintptr_t)this_cpu_info;