Commit 11c8b3f8 authored by Paulo Alcantara's avatar Paulo Alcantara Committed by Steve French

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: default avatarPaulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 48d240bf
...@@ -269,7 +269,7 @@ static int dfscache_proc_show(struct seq_file *m, void *v) ...@@ -269,7 +269,7 @@ static int dfscache_proc_show(struct seq_file *m, void *v)
list_for_each_entry(t, &ce->tlist, list) { list_for_each_entry(t, &ce->tlist, list) {
seq_printf(m, " %s%s\n", seq_printf(m, " %s%s\n",
t->name, 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) ...@@ -321,7 +321,7 @@ static inline void dump_tgts(const struct cache_entry *ce)
cifs_dbg(FYI, "target list:\n"); cifs_dbg(FYI, "target list:\n");
list_for_each_entry(t, &ce->tlist, list) { list_for_each_entry(t, &ce->tlist, list) {
cifs_dbg(FYI, " %s%s\n", t->name, 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) ...@@ -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 */ /* Return target hint of a DFS cache entry */
static inline char *get_tgt_name(const struct cache_entry *ce) 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); return t ? t->name : ERR_PTR(-ENOENT);
} }
...@@ -470,6 +470,7 @@ static struct cache_dfs_tgt *alloc_target(const char *name, int path_consumed) ...@@ -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, static int copy_ref_data(const struct dfs_info3_param *refs, int numrefs,
struct cache_entry *ce, const char *tgthint) struct cache_entry *ce, const char *tgthint)
{ {
struct cache_dfs_tgt *target;
int i; int i;
ce->ttl = max_t(int, refs[0].ttl, CACHE_MIN_TTL); 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, ...@@ -496,8 +497,9 @@ static int copy_ref_data(const struct dfs_info3_param *refs, int numrefs,
ce->numtgts++; ce->numtgts++;
} }
ce->tgthint = list_first_entry_or_null(&ce->tlist, target = list_first_entry_or_null(&ce->tlist, struct cache_dfs_tgt,
struct cache_dfs_tgt, list); list);
WRITE_ONCE(ce->tgthint, target);
return 0; return 0;
} }
...@@ -712,14 +714,15 @@ void dfs_cache_destroy(void) ...@@ -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, static int update_cache_entry_locked(struct cache_entry *ce, const struct dfs_info3_param *refs,
int numrefs) int numrefs)
{ {
struct cache_dfs_tgt *target;
char *th = NULL;
int rc; int rc;
char *s, *th = NULL;
WARN_ON(!rwsem_is_locked(&htable_rw_lock)); WARN_ON(!rwsem_is_locked(&htable_rw_lock));
if (ce->tgthint) { target = READ_ONCE(ce->tgthint);
s = ce->tgthint->name; if (target) {
th = kstrdup(s, GFP_ATOMIC); th = kstrdup(target->name, GFP_ATOMIC);
if (!th) if (!th)
return -ENOMEM; return -ENOMEM;
} }
...@@ -896,7 +899,7 @@ static int get_targets(struct cache_entry *ce, struct dfs_cache_tgt_list *tl) ...@@ -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; it->it_path_consumed = t->path_consumed;
if (ce->tgthint == t) if (READ_ONCE(ce->tgthint) == t)
list_add(&it->it_list, head); list_add(&it->it_list, head);
else else
list_add_tail(&it->it_list, head); list_add_tail(&it->it_list, head);
...@@ -1052,23 +1055,14 @@ int dfs_cache_update_tgthint(const unsigned int xid, struct cifs_ses *ses, ...@@ -1052,23 +1055,14 @@ int dfs_cache_update_tgthint(const unsigned int xid, struct cifs_ses *ses,
goto out_free_path; goto out_free_path;
} }
up_read(&htable_rw_lock); t = READ_ONCE(ce->tgthint);
down_write(&htable_rw_lock);
ce = lookup_cache_entry(npath);
if (IS_ERR(ce)) {
rc = PTR_ERR(ce);
goto out_unlock;
}
t = ce->tgthint;
if (likely(!strcasecmp(it->it_name, t->name))) if (likely(!strcasecmp(it->it_name, t->name)))
goto out_unlock; goto out_unlock;
list_for_each_entry(t, &ce->tlist, list) { list_for_each_entry(t, &ce->tlist, list) {
if (!strcasecmp(t->name, it->it_name)) { 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__, cifs_dbg(FYI, "%s: new target hint: %s\n", __func__,
it->it_name); it->it_name);
break; break;
...@@ -1076,7 +1070,7 @@ int dfs_cache_update_tgthint(const unsigned int xid, struct cifs_ses *ses, ...@@ -1076,7 +1070,7 @@ int dfs_cache_update_tgthint(const unsigned int xid, struct cifs_ses *ses,
} }
out_unlock: out_unlock:
up_write(&htable_rw_lock); up_read(&htable_rw_lock);
out_free_path: out_free_path:
kfree(npath); kfree(npath);
return rc; return rc;
...@@ -1106,21 +1100,20 @@ void dfs_cache_noreq_update_tgthint(const char *path, const struct dfs_cache_tgt ...@@ -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); cifs_dbg(FYI, "%s: path: %s\n", __func__, path);
if (!down_write_trylock(&htable_rw_lock)) down_read(&htable_rw_lock);
return;
ce = lookup_cache_entry(path); ce = lookup_cache_entry(path);
if (IS_ERR(ce)) if (IS_ERR(ce))
goto out_unlock; goto out_unlock;
t = ce->tgthint; t = READ_ONCE(ce->tgthint);
if (unlikely(!strcasecmp(it->it_name, t->name))) if (unlikely(!strcasecmp(it->it_name, t->name)))
goto out_unlock; goto out_unlock;
list_for_each_entry(t, &ce->tlist, list) { list_for_each_entry(t, &ce->tlist, list) {
if (!strcasecmp(t->name, it->it_name)) { 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__, cifs_dbg(FYI, "%s: new target hint: %s\n", __func__,
it->it_name); it->it_name);
break; break;
...@@ -1128,7 +1121,7 @@ void dfs_cache_noreq_update_tgthint(const char *path, const struct dfs_cache_tgt ...@@ -1128,7 +1121,7 @@ void dfs_cache_noreq_update_tgthint(const char *path, const struct dfs_cache_tgt
} }
out_unlock: out_unlock:
up_write(&htable_rw_lock); up_read(&htable_rw_lock);
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment