mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 20:22:09 +00:00
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:
parent
48d240bf00
commit
11c8b3f849
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user