dcache: get/release read lock in read_seqbegin_or_lock() & friend

This patch modifies read_seqbegin_or_lock() and need_seqretry() to use
newly introduced read_seqlock_excl() and read_sequnlock_excl()
primitives so that they won't change the sequence number even if they
fall back to take the lock.  This is OK as no change to the protected
data structure is being made.

It will prevent one fallback to lock taking from cascading into a series
of lock taking reducing performance because of the sequence number
change.  It will also allow other sequence readers to go forward while
an exclusive reader lock is taken.

This patch also updates some of the inaccurate comments in the code.

Signed-off-by: Waiman Long <Waiman.Long@hp.com>
To: Alexander Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Waiman Long 2013-09-12 10:55:35 -04:00 committed by Linus Torvalds
parent 1370e97bb2
commit 1812997720
1 changed files with 16 additions and 15 deletions

View File

@ -90,8 +90,8 @@ static struct kmem_cache *dentry_cache __read_mostly;
/** /**
* read_seqbegin_or_lock - begin a sequence number check or locking block * read_seqbegin_or_lock - begin a sequence number check or locking block
* lock: sequence lock * @lock: sequence lock
* seq : sequence number to be checked * @seq : sequence number to be checked
* *
* First try it once optimistically without taking the lock. If that fails, * First try it once optimistically without taking the lock. If that fails,
* take the lock. The sequence number is also used as a marker for deciding * take the lock. The sequence number is also used as a marker for deciding
@ -103,7 +103,7 @@ static inline void read_seqbegin_or_lock(seqlock_t *lock, int *seq)
if (!(*seq & 1)) /* Even */ if (!(*seq & 1)) /* Even */
*seq = read_seqbegin(lock); *seq = read_seqbegin(lock);
else /* Odd */ else /* Odd */
write_seqlock(lock); read_seqlock_excl(lock);
} }
static inline int need_seqretry(seqlock_t *lock, int seq) static inline int need_seqretry(seqlock_t *lock, int seq)
@ -114,7 +114,7 @@ static inline int need_seqretry(seqlock_t *lock, int seq)
static inline void done_seqretry(seqlock_t *lock, int seq) static inline void done_seqretry(seqlock_t *lock, int seq)
{ {
if (seq & 1) if (seq & 1)
write_sequnlock(lock); read_sequnlock_excl(lock);
} }
/* /*
@ -2673,9 +2673,9 @@ static int prepend(char **buffer, int *buflen, const char *str, int namelen)
/** /**
* prepend_name - prepend a pathname in front of current buffer pointer * prepend_name - prepend a pathname in front of current buffer pointer
* buffer: buffer pointer * @buffer: buffer pointer
* buflen: allocated length of the buffer * @buflen: allocated length of the buffer
* name: name string and length qstr structure * @name: name string and length qstr structure
* *
* With RCU path tracing, it may race with d_move(). Use ACCESS_ONCE() to * With RCU path tracing, it may race with d_move(). Use ACCESS_ONCE() to
* make sure that either the old or the new name pointer and length are * make sure that either the old or the new name pointer and length are
@ -2713,14 +2713,15 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name)
* @buffer: pointer to the end of the buffer * @buffer: pointer to the end of the buffer
* @buflen: pointer to buffer length * @buflen: pointer to buffer length
* *
* The function tries to write out the pathname without taking any lock other * The function will first try to write out the pathname without taking any
* than the RCU read lock to make sure that dentries won't go away. It only * lock other than the RCU read lock to make sure that dentries won't go away.
* checks the sequence number of the global rename_lock as any change in the * It only checks the sequence number of the global rename_lock as any change
* dentry's d_seq will be preceded by changes in the rename_lock sequence * in the dentry's d_seq will be preceded by changes in the rename_lock
* number. If the sequence number had been change, it will restart the whole * sequence number. If the sequence number had been changed, it will restart
* pathname back-tracing sequence again. It performs a total of 3 trials of * the whole pathname back-tracing sequence again by taking the rename_lock.
* lockless back-tracing sequences before falling back to take the * In this case, there is no need to take the RCU read lock as the recursive
* rename_lock. * parent pointer references will keep the dentry chain alive as long as no
* rename operation is performed.
*/ */
static int prepend_path(const struct path *path, static int prepend_path(const struct path *path,
const struct path *root, const struct path *root,