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); } _______________________________________________ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel