Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F108592440
D46465.id142547.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
3 KB
Referenced Files
None
Subscribers
None
D46465.id142547.diff
View Options
diff --git a/sys/kern/kern_rangelock.c b/sys/kern/kern_rangelock.c
--- a/sys/kern/kern_rangelock.c
+++ b/sys/kern/kern_rangelock.c
@@ -66,7 +66,7 @@
* trylocks are same as normal locks but do not drain.
*/
-static int rangelock_cheat = 0;
+static int rangelock_cheat = 1;
SYSCTL_INT(_debug, OID_AUTO, rangelock_cheat, CTLFLAG_RWTUN,
&rangelock_cheat, 0,
"");
@@ -82,6 +82,24 @@
#define RL_RET_CHEAT_RLOCKED 0x1100
#define RL_RET_CHEAT_WLOCKED 0x2200
+static void
+rangelock_cheat_drain(struct rangelock *lock)
+{
+ uintptr_t v;
+
+ DROP_GIANT();
+ for (;;) {
+ v = (uintptr_t)atomic_load_ptr(&lock->head);
+ if ((v & RL_CHEAT_DRAINING) == 0)
+ break;
+ sleepq_add(&lock->head, NULL, "ranged1", 0, 0);
+ sleepq_wait(&lock->head, PRI_USER);
+ sleepq_lock(&lock->head);
+ }
+ sleepq_release(&lock->head);
+ PICKUP_GIANT();
+}
+
static bool
rangelock_cheat_lock(struct rangelock *lock, int locktype, bool trylock,
void **cookie)
@@ -99,17 +117,7 @@
}
sleepq_lock(&lock->head);
drain1:
- DROP_GIANT();
- for (;;) {
- v = (uintptr_t)atomic_load_ptr(&lock->head);
- if ((v & RL_CHEAT_DRAINING) == 0)
- break;
- sleepq_add(&lock->head, NULL, "ranged1", 0, 0);
- sleepq_wait(&lock->head, PRI_USER);
- sleepq_lock(&lock->head);
- }
- sleepq_release(&lock->head);
- PICKUP_GIANT();
+ rangelock_cheat_drain(lock);
return (false);
}
@@ -744,6 +752,34 @@
return (rangelock_lock_int(lock, true, start, end, RL_LOCK_WRITE));
}
+/*
+ * If the caller asserts that it can obtain the range locks on the
+ * same lock simultaneously, switch to the non-cheat mode. Cheat mode
+ * cannot handle it, hanging in drain or trylock retries.
+ */
+void
+rangelock_may_recurse(struct rangelock *lock)
+{
+ uintptr_t v, x;
+
+ v = (uintptr_t)atomic_load_ptr(&lock->head);
+ if ((v & RL_CHEAT_CHEATING) == 0)
+ return;
+
+ sleepq_lock(&lock->head);
+ for (;;) {
+ if ((v & RL_CHEAT_CHEATING) == 0) {
+ sleepq_release(&lock->head);
+ return;
+ }
+ x = v | RL_CHEAT_DRAINING;
+ if (atomic_fcmpset_rel_ptr(&lock->head, &v, x) != 0)
+ break;
+ }
+
+ rangelock_cheat_drain(lock);
+}
+
#ifdef INVARIANT_SUPPORT
void
_rangelock_cookie_assert(void *cookie, int what, const char *file, int line)
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -4978,11 +4978,13 @@
* If infp and outfp refer to the same file, the byte ranges cannot
* overlap.
*/
- if (invp == outvp && ((savinoff <= savoutoff && savinoff + len >
- savoutoff) || (savinoff > savoutoff && savoutoff + len >
- savinoff))) {
- error = EINVAL;
- goto out;
+ if (invp == outvp) {
+ if ((savinoff <= savoutoff && savinoff + len > savoutoff) ||
+ (savinoff > savoutoff && savoutoff + len > savinoff)) {
+ error = EINVAL;
+ goto out;
+ }
+ rangelock_may_recurse(&invp->v_rl);
}
/* Range lock the byte ranges for both invp and outvp. */
diff --git a/sys/sys/rangelock.h b/sys/sys/rangelock.h
--- a/sys/sys/rangelock.h
+++ b/sys/sys/rangelock.h
@@ -66,6 +66,7 @@
void *rangelock_trywlock(struct rangelock *lock, vm_ooffset_t start,
vm_ooffset_t end);
void rangelock_entry_free(struct rl_q_entry *e);
+void rangelock_may_recurse(struct rangelock *lock);
#if defined(INVARIANTS) || defined(INVARIANT_SUPPORT)
void _rangelock_cookie_assert(void *cookie, int what, const char *file,
int line);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Jan 27, 6:00 PM (4 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16202565
Default Alt Text
D46465.id142547.diff (3 KB)
Attached To
Mode
D46465: kern_copy_file_range(): handle rangelock recursion
Attached
Detach File
Event Timeline
Log In to Comment