fs: Use rename lock and RCU for multi-step operations
The remaining usages for dcache_lock is to allow atomic, multi-step read-side operations over the directory tree by excluding modifications to the tree. Also, to walk in the leaf->root direction in the tree where we don't have a natural d_lock ordering. This could be accomplished by taking every d_lock, but this would mean a huge number of locks and actually gets very tricky. Solve this instead by using the rename seqlock for multi-step read-side operations, retry in case of a rename so we don't walk up the wrong parent. Concurrent dentry insertions are not serialised against. Concurrent deletes are tricky when walking up the directory: our parent might have been deleted when dropping locks so also need to check and retry for that. We can also use the rename lock in cases where livelock is a worry (and it is introduced in subsequent patch). Signed-off-by: Nick Piggin <npiggin@kernel.dk>
This commit is contained in:
@@ -186,16 +186,25 @@ static int autofs4_getpath(struct autofs_sb_info *sbi,
|
||||
{
|
||||
struct dentry *root = sbi->sb->s_root;
|
||||
struct dentry *tmp;
|
||||
char *buf = *name;
|
||||
char *buf;
|
||||
char *p;
|
||||
int len = 0;
|
||||
int len;
|
||||
unsigned seq;
|
||||
|
||||
rename_retry:
|
||||
buf = *name;
|
||||
len = 0;
|
||||
seq = read_seqbegin(&rename_lock);
|
||||
rcu_read_lock();
|
||||
spin_lock(&dcache_lock);
|
||||
for (tmp = dentry ; tmp != root ; tmp = tmp->d_parent)
|
||||
len += tmp->d_name.len + 1;
|
||||
|
||||
if (!len || --len > NAME_MAX) {
|
||||
spin_unlock(&dcache_lock);
|
||||
rcu_read_unlock();
|
||||
if (read_seqretry(&rename_lock, seq))
|
||||
goto rename_retry;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -209,6 +218,9 @@ static int autofs4_getpath(struct autofs_sb_info *sbi,
|
||||
strncpy(p, tmp->d_name.name, tmp->d_name.len);
|
||||
}
|
||||
spin_unlock(&dcache_lock);
|
||||
rcu_read_unlock();
|
||||
if (read_seqretry(&rename_lock, seq))
|
||||
goto rename_retry;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
Reference in New Issue
Block a user