From: Pavel Emelyanov <xemul@xxxxxxxxxx> Subject: [patch 1/3] vfs, dcache: Introduce lighten r/o rename_lock lockers There are some places, that need to _lock_ the rename_lock, but they do it for reading the dentry tree. When doing the write_seqlock they force the existing "willing to restart" readers do the restart, which is not actually required. Introduce two more seqlock helpers, that lock the lock, but do not update the seq count. Signed-off-by: Pavel Emelyanov <xemul@xxxxxxxxxx> Signed-off-by: Cyrill Gorcunov <gorcunov@xxxxxxxxxx> --- fs/dcache.c | 40 ++++++++++++++++++++-------------------- include/linux/seqlock.h | 16 ++++++++++++++++ 2 files changed, 36 insertions(+), 20 deletions(-) Index: linux-2.6.git/fs/dcache.c =================================================================== --- linux-2.6.git.orig/fs/dcache.c +++ linux-2.6.git/fs/dcache.c @@ -1089,18 +1089,18 @@ resume: if (!locked && read_seqretry(&rename_lock, seq)) goto rename_retry; if (locked) - write_sequnlock(&rename_lock); + read_sequnlock(&rename_lock); return 0; /* No mount points found in tree */ positive: if (!locked && read_seqretry(&rename_lock, seq)) goto rename_retry; if (locked) - write_sequnlock(&rename_lock); + read_sequnlock(&rename_lock); return 1; rename_retry: locked = 1; - write_seqlock(&rename_lock); + read_seqlock(&rename_lock); goto again; } EXPORT_SYMBOL(have_submounts); @@ -1191,14 +1191,14 @@ out: if (!locked && read_seqretry(&rename_lock, seq)) goto rename_retry; if (locked) - write_sequnlock(&rename_lock); + read_sequnlock(&rename_lock); return found; rename_retry: if (found) return found; locked = 1; - write_seqlock(&rename_lock); + read_seqlock(&rename_lock); goto again; } @@ -2562,9 +2562,9 @@ char *__d_path(const struct path *path, int error; prepend(&res, &buflen, "\0", 1); - write_seqlock(&rename_lock); + read_seqlock(&rename_lock); error = prepend_path(path, root, &res, &buflen); - write_sequnlock(&rename_lock); + read_sequnlock(&rename_lock); if (error) return ERR_PTR(error); @@ -2626,12 +2626,12 @@ char *d_path(const struct path *path, ch return path->dentry->d_op->d_dname(path->dentry, buf, buflen); get_fs_root(current->fs, &root); - write_seqlock(&rename_lock); + read_seqlock(&rename_lock); tmp = root; error = path_with_deleted(path, &tmp, &res, &buflen); if (error) res = ERR_PTR(error); - write_sequnlock(&rename_lock); + read_sequnlock(&rename_lock); path_put(&root); return res; } @@ -2657,12 +2657,12 @@ char *d_path_with_unreachable(const stru return path->dentry->d_op->d_dname(path->dentry, buf, buflen); get_fs_root(current->fs, &root); - write_seqlock(&rename_lock); + read_seqlock(&rename_lock); tmp = root; error = path_with_deleted(path, &tmp, &res, &buflen); if (!error && !path_equal(&tmp, &root)) error = prepend_unreachable(&res, &buflen); - write_sequnlock(&rename_lock); + read_sequnlock(&rename_lock); path_put(&root); if (error) res = ERR_PTR(error); @@ -2729,9 +2729,9 @@ char *dentry_path_raw(struct dentry *den { char *retval; - write_seqlock(&rename_lock); + read_seqlock(&rename_lock); retval = __dentry_path(dentry, buf, buflen); - write_sequnlock(&rename_lock); + read_sequnlock(&rename_lock); return retval; } @@ -2742,7 +2742,7 @@ char *dentry_path(struct dentry *dentry, char *p = NULL; char *retval; - write_seqlock(&rename_lock); + read_seqlock(&rename_lock); if (d_unlinked(dentry)) { p = buf + buflen; if (prepend(&p, &buflen, "//deleted", 10) != 0) @@ -2750,7 +2750,7 @@ char *dentry_path(struct dentry *dentry, buflen++; } retval = __dentry_path(dentry, buf, buflen); - write_sequnlock(&rename_lock); + read_sequnlock(&rename_lock); if (!IS_ERR(retval) && p) *p = '/'; /* restore '/' overriden with '\0' */ return retval; @@ -2788,7 +2788,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, b get_fs_root_and_pwd(current->fs, &root, &pwd); error = -ENOENT; - write_seqlock(&rename_lock); + read_seqlock(&rename_lock); if (!d_unlinked(pwd.dentry)) { unsigned long len; struct path tmp = root; @@ -2797,7 +2797,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, b prepend(&cwd, &buflen, "\0", 1); error = prepend_path(&pwd, &tmp, &cwd, &buflen); - write_sequnlock(&rename_lock); + read_sequnlock(&rename_lock); if (error) goto out; @@ -2817,7 +2817,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, b error = -EFAULT; } } else { - write_sequnlock(&rename_lock); + read_sequnlock(&rename_lock); } out: @@ -2947,12 +2947,12 @@ resume: if (!locked && read_seqretry(&rename_lock, seq)) goto rename_retry; if (locked) - write_sequnlock(&rename_lock); + read_sequnlock(&rename_lock); return; rename_retry: locked = 1; - write_seqlock(&rename_lock); + read_seqlock(&rename_lock); goto again; } Index: linux-2.6.git/include/linux/seqlock.h =================================================================== --- linux-2.6.git.orig/include/linux/seqlock.h +++ linux-2.6.git/include/linux/seqlock.h @@ -108,6 +108,22 @@ static __always_inline int read_seqretry return unlikely(sl->sequence != start); } +/* + * Lock/unlock the critical section against updates but + * no sequence counter altering, so the other lockless + * readers will not have to restart reading data if + * read-only-lock occured. + */ + +static __always_inline void read_seqlock(seqlock_t *sl) +{ + spin_lock(&sl->lock); +} + +static __always_inline void read_sequnlock(seqlock_t *sl) +{ + spin_unlock(&sl->lock); +} /* * Version using sequence counter only. -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html