-
-
Save agentzh/7a9095fe5f720a155b3e6eabe6a3fab3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/runtime/linux/loc2c-runtime.h b/runtime/linux/loc2c-runtime.h | |
index 0270fa1a0..718b0fc15 100644 | |
--- a/runtime/linux/loc2c-runtime.h | |
+++ b/runtime/linux/loc2c-runtime.h | |
@@ -380,6 +380,15 @@ static inline int __stp_deref_nocheck_(u64 *pv, size_t size, void *addr) | |
{ | |
u64 v = 0; | |
int r = -EFAULT; | |
+ struct mm_struct *mm = current->mm; | |
+ | |
+ if (mm) { | |
+ // The down_read() function can sleep, so we'll call | |
+ // down_read_trylock() instead, which can fail. | |
+ if (! down_read_trylock(&mm->mmap_sem)) { | |
+ return -EBUSY; | |
+ } | |
+ } | |
switch (size) | |
{ | |
@@ -400,6 +409,9 @@ static inline int __stp_deref_nocheck_(u64 *pv, size_t size, void *addr) | |
#endif | |
} | |
+ if (mm) | |
+ up_read(&mm->mmap_sem); | |
+ | |
*pv = v; | |
return r; | |
} | |
@@ -529,8 +541,12 @@ static inline int _stp_deref_nofault_(u64 *pv, size_t size, void *addr, | |
default: \ | |
__stp_get_user_bad(); \ | |
} \ | |
- if (_e) \ | |
- DEREF_FAULT(addr); \ | |
+ if (_e) { \ | |
+ if (_e == -EBUSY) \ | |
+ DEREF_BUSY(addr); \ | |
+ else \ | |
+ DEREF_FAULT(addr); \ | |
+ } \ | |
_v; \ | |
}) | |
@@ -773,6 +789,17 @@ static inline long _stp_deref_string_nofault(char *dst, const char *addr, | |
err = 1; | |
else | |
{ | |
+ struct mm_struct *mm = current->mm; | |
+ if (mm) { | |
+ // The down_read() function can sleep, so we'll call | |
+ // down_read_trylock() instead, which can fail. | |
+ if (! down_read_trylock(&mm->mmap_sem)) { | |
+ pagefault_enable(); | |
+ set_fs(oldfs); | |
+ return -EBUSY; | |
+ } | |
+ } | |
+ | |
/* Reduce len by 1 to leave room for '\0' terminator. */ | |
for (i = 0; i + 1 < len; ++i) | |
{ | |
@@ -783,6 +810,10 @@ static inline long _stp_deref_string_nofault(char *dst, const char *addr, | |
if (dst) | |
*dst++ = v; | |
} | |
+ | |
+ if (mm) | |
+ up_read(&mm->mmap_sem); | |
+ | |
if (!err && dst) | |
*dst = '\0'; | |
} | |
diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h | |
index 0502d5a07..7d5f9c7b1 100644 | |
--- a/runtime/loc2c-runtime.h | |
+++ b/runtime/loc2c-runtime.h | |
@@ -232,10 +232,19 @@ | |
#if STP_SKIP_BADVARS | |
+#define DEREF_BUSY(addr) ({0; }) | |
#define DEREF_FAULT(addr) ({0; }) | |
#define STORE_DEREF_FAULT(addr) ({0; }) | |
#define CATCH_DEREF_FAULT() ({0; }) | |
#else | |
+#define DEREF_BUSY(addr) ({ \ | |
+ snprintf(c->error_buffer, sizeof(c->error_buffer), \ | |
+ STAP_MSG_LOC2C_00, (int)current->tgid, \ | |
+ (long)(intptr_t)(addr)); \ | |
+ c->last_error = c->error_buffer; \ | |
+ goto deref_fault; \ | |
+ }) | |
+ | |
#define DEREF_FAULT(addr) ({ \ | |
snprintf(c->error_buffer, sizeof(c->error_buffer), \ | |
STAP_MSG_LOC2C_01, (long)(intptr_t)(addr)); \ | |
diff --git a/tapset/uconversions.stp b/tapset/uconversions.stp | |
index 83790e992..8654821d2 100644 | |
--- a/tapset/uconversions.stp | |
+++ b/tapset/uconversions.stp | |
@@ -124,9 +124,14 @@ function user_string_n:string (addr:long, n:long) | |
(char __user *) (uintptr_t) STAP_ARG_addr, len); | |
if (rc < 0) { | |
strlcpy(STAP_RETVALUE, "<unknown>", MAXSTRINGLEN); | |
- snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), | |
- "user string copy fault %ld at 0x%lx [man error::fault]", rc, | |
- (unsigned long) (uintptr_t) STAP_ARG_addr); | |
+ if (rc == -EBUSY) | |
+ snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), | |
+ "mm sem busy in user string copy %ld at 0x%lx [man error::fault]", rc, | |
+ (uintptr_t) STAP_ARG_addr); | |
+ else | |
+ snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), | |
+ "user string copy fault %ld at 0x%lx [man error::fault]", rc, | |
+ (uintptr_t) STAP_ARG_addr); | |
CONTEXT->last_error = CONTEXT->error_buffer; | |
} else | |
STAP_RETVALUE[len - 1] = '\0'; | |
diff --git a/translate.cxx b/translate.cxx | |
index a29d9da29..b504066b9 100644 | |
--- a/translate.cxx | |
+++ b/translate.cxx | |
@@ -7862,6 +7862,8 @@ void translate_runtime(systemtap_session& s) | |
<< lex_cast_qstring(_("myproc-unprivileged tapset function called " | |
"without is_myproc checking for pid %d (euid %d)")); | |
+ s.op->newline() << "#define STAP_MSG_LOC2C_00 " | |
+ << lex_cast_qstring(_("pid %d: mm sem busy [man error::fault] at 0x%lx")); | |
s.op->newline() << "#define STAP_MSG_LOC2C_01 " | |
<< lex_cast_qstring(_("read fault [man error::fault] at 0x%lx")); | |
s.op->newline() << "#define STAP_MSG_LOC2C_02 " |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment