cifs: don't take exclusive lock for updating target hints

Avoid contention while updating dfs target hints.  This should be
perfectly fine to update them under shared locks.

Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
Paulo Alcantara 2023-01-17 19:00:39 -03:00 committed by Steve French
parent 48d240bf00
commit 11c8b3f849

View File

@ -269,7 +269,7 @@ static int dfscache_proc_show(struct seq_file *m, void *v)
list_for_each_entry(t, &ce->tlist, list) {
seq_printf(m, " %s%s\n",
t->name,
ce->tgthint == t ? " (target hint)" : "");
READ_ONCE(ce->tgthint) == t ? " (target hint)" : "");
}
}
}
@ -321,7 +321,7 @@ static inline void dump_tgts(const struct cache_entry *ce)
cifs_dbg(FYI, "target list:\n");
list_for_each_entry(t, &ce->tlist, list) {
cifs_dbg(FYI, " %s%s\n", t->name,
ce->tgthint == t ? " (target hint)" : "");
READ_ONCE(ce->tgthint) == t ? " (target hint)" : "");
}
}
@ -427,7 +427,7 @@ static int cache_entry_hash(const void *data, int size, unsigned int *hash)
/* Return target hint of a DFS cache entry */
static inline char *get_tgt_name(const struct cache_entry *ce)
{
struct cache_dfs_tgt *t = ce->tgthint;
struct cache_dfs_tgt *t = READ_ONCE(ce->tgthint);
return t ? t->name : ERR_PTR(-ENOENT);
}
@ -470,6 +470,7 @@ static struct cache_dfs_tgt *alloc_target(const char *name, int path_consumed)
static int copy_ref_data(const struct dfs_info3_param *refs, int numrefs,
struct cache_entry *ce, const char *tgthint)
{
struct cache_dfs_tgt *target;
int i;
ce->ttl = max_t(int, refs[0].ttl, CACHE_MIN_TTL);
@ -496,8 +497,9 @@ static int copy_ref_data(const struct dfs_info3_param *refs, int numrefs,
ce->numtgts++;
}
ce->tgthint = list_first_entry_or_null(&ce->tlist,
struct cache_dfs_tgt, list);
target = list_first_entry_or_null(&ce->tlist, struct cache_dfs_tgt,
list);
WRITE_ONCE(ce->tgthint, target);
return 0;
}
@ -712,14 +714,15 @@ void dfs_cache_destroy(void)
static int update_cache_entry_locked(struct cache_entry *ce, const struct dfs_info3_param *refs,
int numrefs)
{
struct cache_dfs_tgt *target;
char *th = NULL;
int rc;
char *s, *th = NULL;
WARN_ON(!rwsem_is_locked(&htable_rw_lock));
if (ce->tgthint) {
s = ce->tgthint->name;
th = kstrdup(s, GFP_ATOMIC);
target = READ_ONCE(ce->tgthint);
if (target) {
th = kstrdup(target->name, GFP_ATOMIC);
if (!th)
return -ENOMEM;
}
@ -896,7 +899,7 @@ static int get_targets(struct cache_entry *ce, struct dfs_cache_tgt_list *tl)
}
it->it_path_consumed = t->path_consumed;
if (ce->tgthint == t)
if (READ_ONCE(ce->tgthint) == t)
list_add(&it->it_list, head);
else
list_add_tail(&it->it_list, head);
@ -1052,23 +1055,14 @@ int dfs_cache_update_tgthint(const unsigned int xid, struct cifs_ses *ses,
goto out_free_path;
}
up_read(&htable_rw_lock);
down_write(&htable_rw_lock);
ce = lookup_cache_entry(npath);
if (IS_ERR(ce)) {
rc = PTR_ERR(ce);
goto out_unlock;
}
t = ce->tgthint;
t = READ_ONCE(ce->tgthint);
if (likely(!strcasecmp(it->it_name, t->name)))
goto out_unlock;
list_for_each_entry(t, &ce->tlist, list) {
if (!strcasecmp(t->name, it->it_name)) {
ce->tgthint = t;
WRITE_ONCE(ce->tgthint, t);
cifs_dbg(FYI, "%s: new target hint: %s\n", __func__,
it->it_name);
break;
@ -1076,7 +1070,7 @@ int dfs_cache_update_tgthint(const unsigned int xid, struct cifs_ses *ses,
}
out_unlock:
up_write(&htable_rw_lock);
up_read(&htable_rw_lock);
out_free_path:
kfree(npath);
return rc;
@ -1106,21 +1100,20 @@ void dfs_cache_noreq_update_tgthint(const char *path, const struct dfs_cache_tgt
cifs_dbg(FYI, "%s: path: %s\n", __func__, path);
if (!down_write_trylock(&htable_rw_lock))
return;
down_read(&htable_rw_lock);
ce = lookup_cache_entry(path);
if (IS_ERR(ce))
goto out_unlock;
t = ce->tgthint;
t = READ_ONCE(ce->tgthint);
if (unlikely(!strcasecmp(it->it_name, t->name)))
goto out_unlock;
list_for_each_entry(t, &ce->tlist, list) {
if (!strcasecmp(t->name, it->it_name)) {
ce->tgthint = t;
WRITE_ONCE(ce->tgthint, t);
cifs_dbg(FYI, "%s: new target hint: %s\n", __func__,
it->it_name);
break;
@ -1128,7 +1121,7 @@ void dfs_cache_noreq_update_tgthint(const char *path, const struct dfs_cache_tgt
}
out_unlock:
up_write(&htable_rw_lock);
up_read(&htable_rw_lock);
}
/**