On Fri, 25 Feb 2022 09:47:16 +0800 Hillf Danton wrote: > On Thu, 24 Feb 2022 16:47:30 +0800 Hillf Danton wrote: > > On Sat, 8 Jan 2022 08:46:17 -0800 > > > From: Tim Murray <timmur...@google.com> > > > > > > f2fs rw_semaphores work better if writers can starve readers, > > > especially for the checkpoint thread, because writers are strictly > > > more important than reader threads. This prevents significant priority > > > inversion between low-priority readers that blocked while trying to > > > acquire the read lock and a second acquisition of the write lock that > > > might be blocking high priority work. > > > > > > Signed-off-by: Tim Murray <timmur...@google.com> > > > Signed-off-by: Jaegeuk Kim <jaeg...@kernel.org> > > > --- > > > > ... > > > > > +/* > > > + * An implementation of an rwsem that is explicitly unfair to readers. > > > This > > > + * prevents priority inversion when a low-priority reader acquires the > > > read lock > > > + * while sleeping on the write lock but the write lock is needed by > > > + * higher-priority clients. > > > + */ > > > + > > > +struct f2fs_rwsem { > > > + struct rw_semaphore internal_rwsem; > > > + wait_queue_head_t read_waiters; > > > +}; > > > > ... > > > > > +static inline void f2fs_down_read(struct f2fs_rwsem *sem) > > > +{ > > > + wait_event(sem->read_waiters, down_read_trylock(&sem->internal_rwsem)); > > > +} > > > + > > > +static inline int f2fs_down_read_trylock(struct f2fs_rwsem *sem) > > > +{ > > > + return down_read_trylock(&sem->internal_rwsem); > > > +} > > > + > > > +static inline void f2fs_up_read(struct f2fs_rwsem *sem) > > > +{ > > > + up_read(&sem->internal_rwsem); > > > +} > > > + > > > +static inline void f2fs_down_write(struct f2fs_rwsem *sem) > > > +{ > > > + down_write(&sem->internal_rwsem); > > > +} > > > + > > > +static inline int f2fs_down_write_trylock(struct f2fs_rwsem *sem) > > > +{ > > > + return down_write_trylock(&sem->internal_rwsem); > > > +} > > > + > > > +static inline void f2fs_up_write(struct f2fs_rwsem *sem) > > > +{ > > > + up_write(&sem->internal_rwsem); > > > + wake_up_all(&sem->read_waiters); > > > +} > > > + > > > > Here is my two cents, the unfair rwsem derived from lock_sock(), which has > > no link to rwsem. > > > > Only for thoughts now. > > > > Hillf > > > > struct unfair_rwsem { > > spinlock_t lock; > > int owner; /* < 0 writer, > 0 readers */ > > > > struct list_head reader, writer; /* read/write waiters */ > > > > #ifdef CONFIG_DEBUG_LOCK_ALLOC > > struct lockdep_map dep_map; > > #endif > > }; > > > > struct unfair_rwsem_wait { > > struct list_head node; > > struct task_struct *task; > > }; > > > > static void lock_unfair_rwsem(struct unfair_rwsem *us, int read) > > { > > struct unfair_rwsem_wait wait; > > > > mutex_acquire(&us->dep_map, 0, 0, _RET_IP_); > > might_sleep(); > > wait.task = current; > > for (;;) { > > spin_lock(&us->lock); > > if (read) { > > if (us->owner >= 0) { > > us->owner++; > > spin_unlock(&us->lock); > > return; > > } > > list_add_tail(&wait.node, &us->reader); > > } else { > > if (us->owner == 0) { > > us->owner--; > > spin_unlock(&us->lock); > > return; > > } > > list_add_tail(&wait.node, &us->writer); > > } > > set_current_state(TASK_UNINTERRUPTIBLE); > > spin_unlock(&us->lock); > > schedule(); > > } > > } > > > > void down_read_unfair_rwsem(struct unfair_rwsem *us) > > { > > lock_unfair_rwsem(us, 1); > > } > > > > void down_write_unfair_rwsem(struct unfair_rwsem *us) > > { > > lock_unfair_rwsem(us, 0); > > } > > > > static void unlock_unfair_rwsem(struct unfair_rwsem *us, int read) > > { > > struct list_head *head = NULL; > > int all = 0; > > > > spin_lock(&us->lock); > > if (us->owner < 0) { > > BUG_ON(read); > > us->owner++; > > BUG_ON(0 != us->owner); > > > > if (!list_empty(&us->writer)) > > head = &us->writer; > > else if (!list_empty(&us->reader)) { > > head = &us->reader; > > all = 1; > > } > > } else if (us->owner > 0) { > > BUG_ON(!read); > > BUG_ON(!list_empty(&us->reader)); > > us->owner--; > > if (us->owner == 0) > > if (!list_empty(&us->writer)) > > head = &us->writer; > > } else > > BUG_ON(1); > > > > mutex_release(&us->dep_map, _RET_IP_); > > if (head) { > > struct unfair_rwsem_wait *wait; > > do { > > wait = list_first_entry(head, struct unfair_rwsem_wait, > > node); > > list_del(&wait->node); > > wake_up_process(wait->task); > > } while (all && !list_empty(head)); > > } > > spin_unlock(&us->lock); > > } > > > > void up_write_unfair_rwsem(struct unfair_rwsem *us) > > { > > unlock_unfair_rwsem(us, 0); > > } > > > > void up_read_unfair_rwsem(struct unfair_rwsem *us) > > { > > unlock_unfair_rwsem(us, 1); > > } > > > > And make unfair rwsem more unfair by setting lock owner for write waiter, > in addition to prefering to wake up write waiter over read waiter. > > Hillf > > --- x/unfair_rwsem.c > +++ y/unfair_rwsem.c > @@ -42,6 +42,8 @@ static void lock_unfair_rwsem(struct unf > set_current_state(TASK_UNINTERRUPTIBLE); > spin_unlock(&us->lock); > schedule(); > + if (!read) > + return; /* because this is unfair rwsem */ > } > } > > @@ -88,8 +90,15 @@ static void unlock_unfair_rwsem(struct u > do { > wait = list_first_entry(head, struct unfair_rwsem_wait, > node); > list_del(&wait->node); > - wake_up_process(wait->task); > - } while (all && !list_empty(head)); > + if (all) > + wake_up_process(wait->task); > + else { > + /* for the sake of unfairness */ > + us->owner = -1; > + wake_up_process(wait->task); > + break; > + } > + } while (!list_empty(head)); > } > spin_unlock(&us->lock); > } >
Add the trylock method to unfair rwsem. Hillf --- x/unfair_rwsem.c +++ y/unfair_rwsem.c @@ -113,3 +115,37 @@ void up_read_unfair_rwsem(struct unfair_ unlock_unfair_rwsem(us, 1); } +static bool trylock_unfair_rwsem(struct unfair_rwsem *us, int read) +{ + bool rc = false; + + if (!spin_trylock(&us->lock)) + return false; + + if (read) { + if (us->owner >= 0) { + rc = true; + us->owner++; + } + } else { + if (us->owner == 0) { + rc = true; + us->owner--; + } + } + spin_unlock(&us->lock); + + if (rc) + mutex_acquire(&us->dep_map, 0, 1, _RET_IP_); + return rc; +} + +bool try_down_write_unfair_rwsem(struct unfair_rwsem *us) +{ + return trylock_unfair_rwsem(us, 0); +} + +bool try_down_read_unfair_rwsem(struct unfair_rwsem *us) +{ + return trylock_unfair_rwsem(us, 1); +} _______________________________________________ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel