From 3abebc503a5148072052c229c6b04b329a420ecd Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Tue, 14 Feb 2023 08:49:14 -0500 Subject: [PATCH 001/201] net/sched: Retire tcindex classifier commit 8c710f75256bb3cf05ac7b1672c82b92c43f3d28 upstream. The tcindex classifier has served us well for about a quarter of a century but has not been getting much TLC due to lack of known users. Most recently it has become easy prey to syzkaller. For this reason, we are retiring it. Signed-off-by: Jamal Hadi Salim Acked-by: Jiri Pirko Signed-off-by: Paolo Abeni Signed-off-by: Greg Kroah-Hartman --- net/sched/Kconfig | 11 - net/sched/Makefile | 1 - net/sched/cls_tcindex.c | 741 ------------------ .../tc-testing/tc-tests/filters/tcindex.json | 227 ------ 4 files changed, 980 deletions(-) delete mode 100644 net/sched/cls_tcindex.c delete mode 100644 tools/testing/selftests/tc-testing/tc-tests/filters/tcindex.json diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 4662a6ce8a7e..bcdd6e925343 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -503,17 +503,6 @@ config NET_CLS_BASIC To compile this code as a module, choose M here: the module will be called cls_basic. -config NET_CLS_TCINDEX - tristate "Traffic-Control Index (TCINDEX)" - select NET_CLS - help - Say Y here if you want to be able to classify packets based on - traffic control indices. You will want this feature if you want - to implement Differentiated Services together with DSMARK. - - To compile this code as a module, choose M here: the - module will be called cls_tcindex. - config NET_CLS_ROUTE4 tristate "Routing decision (ROUTE)" depends on INET diff --git a/net/sched/Makefile b/net/sched/Makefile index dd14ef413fda..b7dbac5c519f 100644 --- a/net/sched/Makefile +++ b/net/sched/Makefile @@ -70,7 +70,6 @@ obj-$(CONFIG_NET_CLS_U32) += cls_u32.o obj-$(CONFIG_NET_CLS_ROUTE4) += cls_route.o obj-$(CONFIG_NET_CLS_FW) += cls_fw.o obj-$(CONFIG_NET_CLS_RSVP) += cls_rsvp.o -obj-$(CONFIG_NET_CLS_TCINDEX) += cls_tcindex.o obj-$(CONFIG_NET_CLS_RSVP6) += cls_rsvp6.o obj-$(CONFIG_NET_CLS_BASIC) += cls_basic.o obj-$(CONFIG_NET_CLS_FLOW) += cls_flow.o diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c deleted file mode 100644 index eea8e185fcdb..000000000000 --- a/net/sched/cls_tcindex.c +++ /dev/null @@ -1,741 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * net/sched/cls_tcindex.c Packet classifier for skb->tc_index - * - * Written 1998,1999 by Werner Almesberger, EPFL ICA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Passing parameters to the root seems to be done more awkwardly than really - * necessary. At least, u32 doesn't seem to use such dirty hacks. To be - * verified. FIXME. - */ - -#define PERFECT_HASH_THRESHOLD 64 /* use perfect hash if not bigger */ -#define DEFAULT_HASH_SIZE 64 /* optimized for diffserv */ - - -struct tcindex_data; - -struct tcindex_filter_result { - struct tcf_exts exts; - struct tcf_result res; - struct tcindex_data *p; - struct rcu_work rwork; -}; - -struct tcindex_filter { - u16 key; - struct tcindex_filter_result result; - struct tcindex_filter __rcu *next; - struct rcu_work rwork; -}; - - -struct tcindex_data { - struct tcindex_filter_result *perfect; /* perfect hash; NULL if none */ - struct tcindex_filter __rcu **h; /* imperfect hash; */ - struct tcf_proto *tp; - u16 mask; /* AND key with mask */ - u32 shift; /* shift ANDed key to the right */ - u32 hash; /* hash table size; 0 if undefined */ - u32 alloc_hash; /* allocated size */ - u32 fall_through; /* 0: only classify if explicit match */ - refcount_t refcnt; /* a temporary refcnt for perfect hash */ - struct rcu_work rwork; -}; - -static inline int tcindex_filter_is_set(struct tcindex_filter_result *r) -{ - return tcf_exts_has_actions(&r->exts) || r->res.classid; -} - -static void tcindex_data_get(struct tcindex_data *p) -{ - refcount_inc(&p->refcnt); -} - -static void tcindex_data_put(struct tcindex_data *p) -{ - if (refcount_dec_and_test(&p->refcnt)) { - kfree(p->perfect); - kfree(p->h); - kfree(p); - } -} - -static struct tcindex_filter_result *tcindex_lookup(struct tcindex_data *p, - u16 key) -{ - if (p->perfect) { - struct tcindex_filter_result *f = p->perfect + key; - - return tcindex_filter_is_set(f) ? f : NULL; - } else if (p->h) { - struct tcindex_filter __rcu **fp; - struct tcindex_filter *f; - - fp = &p->h[key % p->hash]; - for (f = rcu_dereference_bh_rtnl(*fp); - f; - fp = &f->next, f = rcu_dereference_bh_rtnl(*fp)) - if (f->key == key) - return &f->result; - } - - return NULL; -} - - -static int tcindex_classify(struct sk_buff *skb, const struct tcf_proto *tp, - struct tcf_result *res) -{ - struct tcindex_data *p = rcu_dereference_bh(tp->root); - struct tcindex_filter_result *f; - int key = (skb->tc_index & p->mask) >> p->shift; - - pr_debug("tcindex_classify(skb %p,tp %p,res %p),p %p\n", - skb, tp, res, p); - - f = tcindex_lookup(p, key); - if (!f) { - struct Qdisc *q = tcf_block_q(tp->chain->block); - - if (!p->fall_through) - return -1; - res->classid = TC_H_MAKE(TC_H_MAJ(q->handle), key); - res->class = 0; - pr_debug("alg 0x%x\n", res->classid); - return 0; - } - *res = f->res; - pr_debug("map 0x%x\n", res->classid); - - return tcf_exts_exec(skb, &f->exts, res); -} - - -static void *tcindex_get(struct tcf_proto *tp, u32 handle) -{ - struct tcindex_data *p = rtnl_dereference(tp->root); - struct tcindex_filter_result *r; - - pr_debug("tcindex_get(tp %p,handle 0x%08x)\n", tp, handle); - if (p->perfect && handle >= p->alloc_hash) - return NULL; - r = tcindex_lookup(p, handle); - return r && tcindex_filter_is_set(r) ? r : NULL; -} - -static int tcindex_init(struct tcf_proto *tp) -{ - struct tcindex_data *p; - - pr_debug("tcindex_init(tp %p)\n", tp); - p = kzalloc(sizeof(struct tcindex_data), GFP_KERNEL); - if (!p) - return -ENOMEM; - - p->mask = 0xffff; - p->hash = DEFAULT_HASH_SIZE; - p->fall_through = 1; - refcount_set(&p->refcnt, 1); /* Paired with tcindex_destroy_work() */ - - rcu_assign_pointer(tp->root, p); - return 0; -} - -static void __tcindex_destroy_rexts(struct tcindex_filter_result *r) -{ - tcf_exts_destroy(&r->exts); - tcf_exts_put_net(&r->exts); - tcindex_data_put(r->p); -} - -static void tcindex_destroy_rexts_work(struct work_struct *work) -{ - struct tcindex_filter_result *r; - - r = container_of(to_rcu_work(work), - struct tcindex_filter_result, - rwork); - rtnl_lock(); - __tcindex_destroy_rexts(r); - rtnl_unlock(); -} - -static void __tcindex_destroy_fexts(struct tcindex_filter *f) -{ - tcf_exts_destroy(&f->result.exts); - tcf_exts_put_net(&f->result.exts); - kfree(f); -} - -static void tcindex_destroy_fexts_work(struct work_struct *work) -{ - struct tcindex_filter *f = container_of(to_rcu_work(work), - struct tcindex_filter, - rwork); - - rtnl_lock(); - __tcindex_destroy_fexts(f); - rtnl_unlock(); -} - -static int tcindex_delete(struct tcf_proto *tp, void *arg, bool *last, - bool rtnl_held, struct netlink_ext_ack *extack) -{ - struct tcindex_data *p = rtnl_dereference(tp->root); - struct tcindex_filter_result *r = arg; - struct tcindex_filter __rcu **walk; - struct tcindex_filter *f = NULL; - - pr_debug("tcindex_delete(tp %p,arg %p),p %p\n", tp, arg, p); - if (p->perfect) { - if (!r->res.class) - return -ENOENT; - } else { - int i; - - for (i = 0; i < p->hash; i++) { - walk = p->h + i; - for (f = rtnl_dereference(*walk); f; - walk = &f->next, f = rtnl_dereference(*walk)) { - if (&f->result == r) - goto found; - } - } - return -ENOENT; - -found: - rcu_assign_pointer(*walk, rtnl_dereference(f->next)); - } - tcf_unbind_filter(tp, &r->res); - /* all classifiers are required to call tcf_exts_destroy() after rcu - * grace period, since converted-to-rcu actions are relying on that - * in cleanup() callback - */ - if (f) { - if (tcf_exts_get_net(&f->result.exts)) - tcf_queue_work(&f->rwork, tcindex_destroy_fexts_work); - else - __tcindex_destroy_fexts(f); - } else { - tcindex_data_get(p); - - if (tcf_exts_get_net(&r->exts)) - tcf_queue_work(&r->rwork, tcindex_destroy_rexts_work); - else - __tcindex_destroy_rexts(r); - } - - *last = false; - return 0; -} - -static void tcindex_destroy_work(struct work_struct *work) -{ - struct tcindex_data *p = container_of(to_rcu_work(work), - struct tcindex_data, - rwork); - - tcindex_data_put(p); -} - -static inline int -valid_perfect_hash(struct tcindex_data *p) -{ - return p->hash > (p->mask >> p->shift); -} - -static const struct nla_policy tcindex_policy[TCA_TCINDEX_MAX + 1] = { - [TCA_TCINDEX_HASH] = { .type = NLA_U32 }, - [TCA_TCINDEX_MASK] = { .type = NLA_U16 }, - [TCA_TCINDEX_SHIFT] = { .type = NLA_U32 }, - [TCA_TCINDEX_FALL_THROUGH] = { .type = NLA_U32 }, - [TCA_TCINDEX_CLASSID] = { .type = NLA_U32 }, -}; - -static int tcindex_filter_result_init(struct tcindex_filter_result *r, - struct tcindex_data *p, - struct net *net) -{ - memset(r, 0, sizeof(*r)); - r->p = p; - return tcf_exts_init(&r->exts, net, TCA_TCINDEX_ACT, - TCA_TCINDEX_POLICE); -} - -static void tcindex_free_perfect_hash(struct tcindex_data *cp); - -static void tcindex_partial_destroy_work(struct work_struct *work) -{ - struct tcindex_data *p = container_of(to_rcu_work(work), - struct tcindex_data, - rwork); - - rtnl_lock(); - if (p->perfect) - tcindex_free_perfect_hash(p); - kfree(p); - rtnl_unlock(); -} - -static void tcindex_free_perfect_hash(struct tcindex_data *cp) -{ - int i; - - for (i = 0; i < cp->hash; i++) - tcf_exts_destroy(&cp->perfect[i].exts); - kfree(cp->perfect); -} - -static int tcindex_alloc_perfect_hash(struct net *net, struct tcindex_data *cp) -{ - int i, err = 0; - - cp->perfect = kcalloc(cp->hash, sizeof(struct tcindex_filter_result), - GFP_KERNEL | __GFP_NOWARN); - if (!cp->perfect) - return -ENOMEM; - - for (i = 0; i < cp->hash; i++) { - err = tcf_exts_init(&cp->perfect[i].exts, net, - TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); - if (err < 0) - goto errout; - cp->perfect[i].p = cp; - } - - return 0; - -errout: - tcindex_free_perfect_hash(cp); - return err; -} - -static int -tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, - u32 handle, struct tcindex_data *p, - struct tcindex_filter_result *r, struct nlattr **tb, - struct nlattr *est, u32 flags, struct netlink_ext_ack *extack) -{ - struct tcindex_filter_result new_filter_result; - struct tcindex_data *cp = NULL, *oldp; - struct tcindex_filter *f = NULL; /* make gcc behave */ - struct tcf_result cr = {}; - int err, balloc = 0; - struct tcf_exts e; - bool update_h = false; - - err = tcf_exts_init(&e, net, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); - if (err < 0) - return err; - err = tcf_exts_validate(net, tp, tb, est, &e, flags, extack); - if (err < 0) - goto errout; - - err = -ENOMEM; - /* tcindex_data attributes must look atomic to classifier/lookup so - * allocate new tcindex data and RCU assign it onto root. Keeping - * perfect hash and hash pointers from old data. - */ - cp = kzalloc(sizeof(*cp), GFP_KERNEL); - if (!cp) - goto errout; - - cp->mask = p->mask; - cp->shift = p->shift; - cp->hash = p->hash; - cp->alloc_hash = p->alloc_hash; - cp->fall_through = p->fall_through; - cp->tp = tp; - refcount_set(&cp->refcnt, 1); /* Paired with tcindex_destroy_work() */ - - if (tb[TCA_TCINDEX_HASH]) - cp->hash = nla_get_u32(tb[TCA_TCINDEX_HASH]); - - if (tb[TCA_TCINDEX_MASK]) - cp->mask = nla_get_u16(tb[TCA_TCINDEX_MASK]); - - if (tb[TCA_TCINDEX_SHIFT]) { - cp->shift = nla_get_u32(tb[TCA_TCINDEX_SHIFT]); - if (cp->shift > 16) { - err = -EINVAL; - goto errout; - } - } - if (!cp->hash) { - /* Hash not specified, use perfect hash if the upper limit - * of the hashing index is below the threshold. - */ - if ((cp->mask >> cp->shift) < PERFECT_HASH_THRESHOLD) - cp->hash = (cp->mask >> cp->shift) + 1; - else - cp->hash = DEFAULT_HASH_SIZE; - } - - if (p->perfect) { - int i; - - if (tcindex_alloc_perfect_hash(net, cp) < 0) - goto errout; - cp->alloc_hash = cp->hash; - for (i = 0; i < min(cp->hash, p->hash); i++) - cp->perfect[i].res = p->perfect[i].res; - balloc = 1; - } - cp->h = p->h; - - err = tcindex_filter_result_init(&new_filter_result, cp, net); - if (err < 0) - goto errout_alloc; - if (r) - cr = r->res; - - err = -EBUSY; - - /* Hash already allocated, make sure that we still meet the - * requirements for the allocated hash. - */ - if (cp->perfect) { - if (!valid_perfect_hash(cp) || - cp->hash > cp->alloc_hash) - goto errout_alloc; - } else if (cp->h && cp->hash != cp->alloc_hash) { - goto errout_alloc; - } - - err = -EINVAL; - if (tb[TCA_TCINDEX_FALL_THROUGH]) - cp->fall_through = nla_get_u32(tb[TCA_TCINDEX_FALL_THROUGH]); - - if (!cp->perfect && !cp->h) - cp->alloc_hash = cp->hash; - - /* Note: this could be as restrictive as if (handle & ~(mask >> shift)) - * but then, we'd fail handles that may become valid after some future - * mask change. While this is extremely unlikely to ever matter, - * the check below is safer (and also more backwards-compatible). - */ - if (cp->perfect || valid_perfect_hash(cp)) - if (handle >= cp->alloc_hash) - goto errout_alloc; - - - err = -ENOMEM; - if (!cp->perfect && !cp->h) { - if (valid_perfect_hash(cp)) { - if (tcindex_alloc_perfect_hash(net, cp) < 0) - goto errout_alloc; - balloc = 1; - } else { - struct tcindex_filter __rcu **hash; - - hash = kcalloc(cp->hash, - sizeof(struct tcindex_filter *), - GFP_KERNEL); - - if (!hash) - goto errout_alloc; - - cp->h = hash; - balloc = 2; - } - } - - if (cp->perfect) { - r = cp->perfect + handle; - } else { - /* imperfect area is updated in-place using rcu */ - update_h = !!tcindex_lookup(cp, handle); - r = &new_filter_result; - } - - if (r == &new_filter_result) { - f = kzalloc(sizeof(*f), GFP_KERNEL); - if (!f) - goto errout_alloc; - f->key = handle; - f->next = NULL; - err = tcindex_filter_result_init(&f->result, cp, net); - if (err < 0) { - kfree(f); - goto errout_alloc; - } - } - - if (tb[TCA_TCINDEX_CLASSID]) { - cr.classid = nla_get_u32(tb[TCA_TCINDEX_CLASSID]); - tcf_bind_filter(tp, &cr, base); - } - - oldp = p; - r->res = cr; - tcf_exts_change(&r->exts, &e); - - rcu_assign_pointer(tp->root, cp); - - if (update_h) { - struct tcindex_filter __rcu **fp; - struct tcindex_filter *cf; - - f->result.res = r->res; - tcf_exts_change(&f->result.exts, &r->exts); - - /* imperfect area bucket */ - fp = cp->h + (handle % cp->hash); - - /* lookup the filter, guaranteed to exist */ - for (cf = rcu_dereference_bh_rtnl(*fp); cf; - fp = &cf->next, cf = rcu_dereference_bh_rtnl(*fp)) - if (cf->key == (u16)handle) - break; - - f->next = cf->next; - - cf = rcu_replace_pointer(*fp, f, 1); - tcf_exts_get_net(&cf->result.exts); - tcf_queue_work(&cf->rwork, tcindex_destroy_fexts_work); - } else if (r == &new_filter_result) { - struct tcindex_filter *nfp; - struct tcindex_filter __rcu **fp; - - f->result.res = r->res; - tcf_exts_change(&f->result.exts, &r->exts); - - fp = cp->h + (handle % cp->hash); - for (nfp = rtnl_dereference(*fp); - nfp; - fp = &nfp->next, nfp = rtnl_dereference(*fp)) - ; /* nothing */ - - rcu_assign_pointer(*fp, f); - } else { - tcf_exts_destroy(&new_filter_result.exts); - } - - if (oldp) - tcf_queue_work(&oldp->rwork, tcindex_partial_destroy_work); - return 0; - -errout_alloc: - if (balloc == 1) - tcindex_free_perfect_hash(cp); - else if (balloc == 2) - kfree(cp->h); - tcf_exts_destroy(&new_filter_result.exts); -errout: - kfree(cp); - tcf_exts_destroy(&e); - return err; -} - -static int -tcindex_change(struct net *net, struct sk_buff *in_skb, - struct tcf_proto *tp, unsigned long base, u32 handle, - struct nlattr **tca, void **arg, u32 flags, - struct netlink_ext_ack *extack) -{ - struct nlattr *opt = tca[TCA_OPTIONS]; - struct nlattr *tb[TCA_TCINDEX_MAX + 1]; - struct tcindex_data *p = rtnl_dereference(tp->root); - struct tcindex_filter_result *r = *arg; - int err; - - pr_debug("tcindex_change(tp %p,handle 0x%08x,tca %p,arg %p),opt %p," - "p %p,r %p,*arg %p\n", - tp, handle, tca, arg, opt, p, r, *arg); - - if (!opt) - return 0; - - err = nla_parse_nested_deprecated(tb, TCA_TCINDEX_MAX, opt, - tcindex_policy, NULL); - if (err < 0) - return err; - - return tcindex_set_parms(net, tp, base, handle, p, r, tb, - tca[TCA_RATE], flags, extack); -} - -static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker, - bool rtnl_held) -{ - struct tcindex_data *p = rtnl_dereference(tp->root); - struct tcindex_filter *f, *next; - int i; - - pr_debug("tcindex_walk(tp %p,walker %p),p %p\n", tp, walker, p); - if (p->perfect) { - for (i = 0; i < p->hash; i++) { - if (!p->perfect[i].res.class) - continue; - if (!tc_cls_stats_dump(tp, walker, p->perfect + i)) - return; - } - } - if (!p->h) - return; - for (i = 0; i < p->hash; i++) { - for (f = rtnl_dereference(p->h[i]); f; f = next) { - next = rtnl_dereference(f->next); - if (!tc_cls_stats_dump(tp, walker, &f->result)) - return; - } - } -} - -static void tcindex_destroy(struct tcf_proto *tp, bool rtnl_held, - struct netlink_ext_ack *extack) -{ - struct tcindex_data *p = rtnl_dereference(tp->root); - int i; - - pr_debug("tcindex_destroy(tp %p),p %p\n", tp, p); - - if (p->perfect) { - for (i = 0; i < p->hash; i++) { - struct tcindex_filter_result *r = p->perfect + i; - - /* tcf_queue_work() does not guarantee the ordering we - * want, so we have to take this refcnt temporarily to - * ensure 'p' is freed after all tcindex_filter_result - * here. Imperfect hash does not need this, because it - * uses linked lists rather than an array. - */ - tcindex_data_get(p); - - tcf_unbind_filter(tp, &r->res); - if (tcf_exts_get_net(&r->exts)) - tcf_queue_work(&r->rwork, - tcindex_destroy_rexts_work); - else - __tcindex_destroy_rexts(r); - } - } - - for (i = 0; p->h && i < p->hash; i++) { - struct tcindex_filter *f, *next; - bool last; - - for (f = rtnl_dereference(p->h[i]); f; f = next) { - next = rtnl_dereference(f->next); - tcindex_delete(tp, &f->result, &last, rtnl_held, NULL); - } - } - - tcf_queue_work(&p->rwork, tcindex_destroy_work); -} - - -static int tcindex_dump(struct net *net, struct tcf_proto *tp, void *fh, - struct sk_buff *skb, struct tcmsg *t, bool rtnl_held) -{ - struct tcindex_data *p = rtnl_dereference(tp->root); - struct tcindex_filter_result *r = fh; - struct nlattr *nest; - - pr_debug("tcindex_dump(tp %p,fh %p,skb %p,t %p),p %p,r %p\n", - tp, fh, skb, t, p, r); - pr_debug("p->perfect %p p->h %p\n", p->perfect, p->h); - - nest = nla_nest_start_noflag(skb, TCA_OPTIONS); - if (nest == NULL) - goto nla_put_failure; - - if (!fh) { - t->tcm_handle = ~0; /* whatever ... */ - if (nla_put_u32(skb, TCA_TCINDEX_HASH, p->hash) || - nla_put_u16(skb, TCA_TCINDEX_MASK, p->mask) || - nla_put_u32(skb, TCA_TCINDEX_SHIFT, p->shift) || - nla_put_u32(skb, TCA_TCINDEX_FALL_THROUGH, p->fall_through)) - goto nla_put_failure; - nla_nest_end(skb, nest); - } else { - if (p->perfect) { - t->tcm_handle = r - p->perfect; - } else { - struct tcindex_filter *f; - struct tcindex_filter __rcu **fp; - int i; - - t->tcm_handle = 0; - for (i = 0; !t->tcm_handle && i < p->hash; i++) { - fp = &p->h[i]; - for (f = rtnl_dereference(*fp); - !t->tcm_handle && f; - fp = &f->next, f = rtnl_dereference(*fp)) { - if (&f->result == r) - t->tcm_handle = f->key; - } - } - } - pr_debug("handle = %d\n", t->tcm_handle); - if (r->res.class && - nla_put_u32(skb, TCA_TCINDEX_CLASSID, r->res.classid)) - goto nla_put_failure; - - if (tcf_exts_dump(skb, &r->exts) < 0) - goto nla_put_failure; - nla_nest_end(skb, nest); - - if (tcf_exts_dump_stats(skb, &r->exts) < 0) - goto nla_put_failure; - } - - return skb->len; - -nla_put_failure: - nla_nest_cancel(skb, nest); - return -1; -} - -static void tcindex_bind_class(void *fh, u32 classid, unsigned long cl, - void *q, unsigned long base) -{ - struct tcindex_filter_result *r = fh; - - tc_cls_bind_class(classid, cl, q, &r->res, base); -} - -static struct tcf_proto_ops cls_tcindex_ops __read_mostly = { - .kind = "tcindex", - .classify = tcindex_classify, - .init = tcindex_init, - .destroy = tcindex_destroy, - .get = tcindex_get, - .change = tcindex_change, - .delete = tcindex_delete, - .walk = tcindex_walk, - .dump = tcindex_dump, - .bind_class = tcindex_bind_class, - .owner = THIS_MODULE, -}; - -static int __init init_tcindex(void) -{ - return register_tcf_proto_ops(&cls_tcindex_ops); -} - -static void __exit exit_tcindex(void) -{ - unregister_tcf_proto_ops(&cls_tcindex_ops); -} - -module_init(init_tcindex) -module_exit(exit_tcindex) -MODULE_LICENSE("GPL"); diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/tcindex.json b/tools/testing/selftests/tc-testing/tc-tests/filters/tcindex.json deleted file mode 100644 index 44901db70376..000000000000 --- a/tools/testing/selftests/tc-testing/tc-tests/filters/tcindex.json +++ /dev/null @@ -1,227 +0,0 @@ -[ - { - "id": "8293", - "name": "Add tcindex filter with default action", - "category": [ - "filter", - "tcindex" - ], - "plugins": { - "requires": "nsPlugin" - }, - "setup": [ - "$TC qdisc add dev $DEV1 ingress" - ], - "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 protocol ip prio 1 tcindex classid 1:1", - "expExitCode": "0", - "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol ip tcindex", - "matchPattern": "^filter parent ffff: protocol ip pref 1 tcindex chain 0 handle 0x0001 classid 1:1", - "matchCount": "1", - "teardown": [ - "$TC qdisc del dev $DEV1 ingress" - ] - }, - { - "id": "7281", - "name": "Add tcindex filter with hash size and pass action", - "category": [ - "filter", - "tcindex" - ], - "plugins": { - "requires": "nsPlugin" - }, - "setup": [ - "$TC qdisc add dev $DEV1 ingress" - ], - "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 protocol ip prio 1 tcindex hash 32 fall_through classid 1:1 action pass", - "expExitCode": "0", - "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol ip tcindex", - "matchPattern": "^filter parent ffff: protocol ip pref.*tcindex chain [0-9]+ handle 0x0001 classid 1:1.*action order [0-9]+: gact action pass", - "matchCount": "1", - "teardown": [ - "$TC qdisc del dev $DEV1 ingress" - ] - }, - { - "id": "b294", - "name": "Add tcindex filter with mask shift and reclassify action", - "category": [ - "filter", - "tcindex" - ], - "plugins": { - "requires": "nsPlugin" - }, - "setup": [ - "$TC qdisc add dev $DEV1 ingress" - ], - "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 protocol ip prio 1 tcindex hash 32 mask 1 shift 2 fall_through classid 1:1 action reclassify", - "expExitCode": "0", - "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol ip tcindex", - "matchPattern": "^filter parent ffff: protocol ip pref.*tcindex chain [0-9]+ handle 0x0001 classid 1:1.*action order [0-9]+: gact action reclassify", - "matchCount": "1", - "teardown": [ - "$TC qdisc del dev $DEV1 ingress" - ] - }, - { - "id": "0532", - "name": "Add tcindex filter with pass_on and continue actions", - "category": [ - "filter", - "tcindex" - ], - "plugins": { - "requires": "nsPlugin" - }, - "setup": [ - "$TC qdisc add dev $DEV1 ingress" - ], - "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 protocol ip prio 1 tcindex hash 32 mask 1 shift 2 pass_on classid 1:1 action continue", - "expExitCode": "0", - "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol ip tcindex", - "matchPattern": "^filter parent ffff: protocol ip pref.*tcindex chain [0-9]+ handle 0x0001 classid 1:1.*action order [0-9]+: gact action continue", - "matchCount": "1", - "teardown": [ - "$TC qdisc del dev $DEV1 ingress" - ] - }, - { - "id": "d473", - "name": "Add tcindex filter with pipe action", - "category": [ - "filter", - "tcindex" - ], - "plugins": { - "requires": "nsPlugin" - }, - "setup": [ - "$TC qdisc add dev $DEV1 ingress" - ], - "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 protocol ip prio 1 tcindex hash 32 mask 1 shift 2 fall_through classid 1:1 action pipe", - "expExitCode": "0", - "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol ip tcindex", - "matchPattern": "^filter parent ffff: protocol ip pref.*tcindex chain [0-9]+ handle 0x0001 classid 1:1.*action order [0-9]+: gact action pipe", - "matchCount": "1", - "teardown": [ - "$TC qdisc del dev $DEV1 ingress" - ] - }, - { - "id": "2940", - "name": "Add tcindex filter with miltiple actions", - "category": [ - "filter", - "tcindex" - ], - "plugins": { - "requires": "nsPlugin" - }, - "setup": [ - "$TC qdisc add dev $DEV1 ingress" - ], - "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 protocol ip prio 7 tcindex hash 32 mask 1 shift 2 fall_through classid 1:1 action skbedit mark 7 pipe action gact drop", - "expExitCode": "0", - "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 7 protocol ip tcindex", - "matchPattern": "^filter parent ffff: protocol ip pref 7 tcindex.*handle 0x0001.*action.*skbedit.*mark 7 pipe.*action.*gact action drop", - "matchCount": "1", - "teardown": [ - "$TC qdisc del dev $DEV1 ingress" - ] - }, - { - "id": "1893", - "name": "List tcindex filters", - "category": [ - "filter", - "tcindex" - ], - "plugins": { - "requires": "nsPlugin" - }, - "setup": [ - "$TC qdisc add dev $DEV1 ingress", - "$TC filter add dev $DEV1 parent ffff: handle 1 protocol ip prio 1 tcindex classid 1:1", - "$TC filter add dev $DEV1 parent ffff: handle 2 protocol ip prio 1 tcindex classid 1:1" - ], - "cmdUnderTest": "$TC filter show dev $DEV1 parent ffff:", - "expExitCode": "0", - "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", - "matchPattern": "handle 0x000[0-9]+ classid 1:1", - "matchCount": "2", - "teardown": [ - "$TC qdisc del dev $DEV1 ingress" - ] - }, - { - "id": "2041", - "name": "Change tcindex filter with pass action", - "category": [ - "filter", - "tcindex" - ], - "plugins": { - "requires": "nsPlugin" - }, - "setup": [ - "$TC qdisc add dev $DEV1 ingress", - "$TC filter add dev $DEV1 parent ffff: handle 1 protocol ip prio 1 tcindex classid 1:1 action drop" - ], - "cmdUnderTest": "$TC filter change dev $DEV1 parent ffff: handle 1 protocol ip prio 1 tcindex classid 1:1 action pass", - "expExitCode": "0", - "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol ip tcindex", - "matchPattern": "handle 0x0001 classid 1:1.*action order [0-9]+: gact action pass", - "matchCount": "1", - "teardown": [ - "$TC qdisc del dev $DEV1 ingress" - ] - }, - { - "id": "9203", - "name": "Replace tcindex filter with pass action", - "category": [ - "filter", - "tcindex" - ], - "plugins": { - "requires": "nsPlugin" - }, - "setup": [ - "$TC qdisc add dev $DEV1 ingress", - "$TC filter add dev $DEV1 parent ffff: handle 1 protocol ip prio 1 tcindex classid 1:1 action drop" - ], - "cmdUnderTest": "$TC filter replace dev $DEV1 parent ffff: handle 1 protocol ip prio 1 tcindex classid 1:1 action pass", - "expExitCode": "0", - "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol ip tcindex", - "matchPattern": "handle 0x0001 classid 1:1.*action order [0-9]+: gact action pass", - "matchCount": "1", - "teardown": [ - "$TC qdisc del dev $DEV1 ingress" - ] - }, - { - "id": "7957", - "name": "Delete tcindex filter with drop action", - "category": [ - "filter", - "tcindex" - ], - "plugins": { - "requires": "nsPlugin" - }, - "setup": [ - "$TC qdisc add dev $DEV1 ingress", - "$TC filter add dev $DEV1 parent ffff: handle 1 protocol ip prio 1 tcindex classid 1:1 action drop" - ], - "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff: handle 1 protocol ip prio 1 tcindex classid 1:1 action drop", - "expExitCode": "0", - "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol ip tcindex", - "matchPattern": "handle 0x0001 classid 1:1.*action order [0-9]+: gact action drop", - "matchCount": "0", - "teardown": [ - "$TC qdisc del dev $DEV1 ingress" - ] - } -] From 6cd37f8232f5e169a723e1d5fbe3b2139c2ef763 Mon Sep 17 00:00:00 2001 From: Jianglei Nie Date: Tue, 29 Nov 2022 16:15:42 +0800 Subject: [PATCH 002/201] auxdisplay: hd44780: Fix potential memory leak in hd44780_remove() [ Upstream commit ddf75a86aba2cfb7ec4497e8692b60c8c8fe0ee7 ] hd44780_probe() allocates a memory chunk for hd with kzalloc() and makes "lcd->drvdata->hd44780" point to it. When we call hd44780_remove(), we should release all relevant memory and resource. But "lcd->drvdata ->hd44780" is not released, which will lead to a memory leak. We should release the "lcd->drvdata->hd44780" in hd44780_remove() to fix the memory leak bug. Fixes: 718e05ed92ec ("auxdisplay: Introduce hd44780_common.[ch]") Reviewed-by: Andy Shevchenko Reported-by: kernel test robot Signed-off-by: Jianglei Nie Signed-off-by: Miguel Ojeda Signed-off-by: Sasha Levin --- drivers/auxdisplay/hd44780.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/auxdisplay/hd44780.c b/drivers/auxdisplay/hd44780.c index 8b2a0eb3f32a..d56a5d508ccd 100644 --- a/drivers/auxdisplay/hd44780.c +++ b/drivers/auxdisplay/hd44780.c @@ -322,8 +322,10 @@ fail1: static int hd44780_remove(struct platform_device *pdev) { struct charlcd *lcd = platform_get_drvdata(pdev); + struct hd44780_common *hdc = lcd->drvdata; charlcd_unregister(lcd); + kfree(hdc->hd44780); kfree(lcd->drvdata); kfree(lcd); From 1f4a325933f81bc52d484bb77e3cb415b0272921 Mon Sep 17 00:00:00 2001 From: Liu Shixin via Jfs-discussion Date: Thu, 3 Nov 2022 11:01:59 +0800 Subject: [PATCH 003/201] fs/jfs: fix shift exponent db_agl2size negative [ Upstream commit fad376fce0af58deebc5075b8539dc05bf639af3 ] As a shift exponent, db_agl2size can not be less than 0. Add the missing check to fix the shift-out-of-bounds bug reported by syzkaller: UBSAN: shift-out-of-bounds in fs/jfs/jfs_dmap.c:2227:15 shift exponent -744642816 is negative Reported-by: syzbot+0be96567042453c0c820@syzkaller.appspotmail.com Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Liu Shixin Signed-off-by: Dave Kleikamp Signed-off-by: Sasha Levin --- fs/jfs/jfs_dmap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index 765838578a72..a3eb1e826947 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c @@ -193,7 +193,8 @@ int dbMount(struct inode *ipbmap) bmp->db_agwidth = le32_to_cpu(dbmp_le->dn_agwidth); bmp->db_agstart = le32_to_cpu(dbmp_le->dn_agstart); bmp->db_agl2size = le32_to_cpu(dbmp_le->dn_agl2size); - if (bmp->db_agl2size > L2MAXL2SIZE - L2MAXAG) { + if (bmp->db_agl2size > L2MAXL2SIZE - L2MAXAG || + bmp->db_agl2size < 0) { err = -EINVAL; goto err_release_metapage; } From d35290addcbac94b076babe0a798a8c043421812 Mon Sep 17 00:00:00 2001 From: Gaosheng Cui Date: Tue, 29 Nov 2022 09:01:46 +0800 Subject: [PATCH 004/201] driver: soc: xilinx: fix memory leak in xlnx_add_cb_for_notify_event() [ Upstream commit 1bea534991b9b35c41848a397666ada436456beb ] The kfree() should be called when memory fails to be allocated for cb_data in xlnx_add_cb_for_notify_event(), otherwise there will be a memory leak, so add kfree() to fix it. Fixes: 05e5ba40ea7a ("driver: soc: xilinx: Add support of multiple callbacks for same event in event management driver") Signed-off-by: Gaosheng Cui Acked-by: Michal Simek Link: https://lore.kernel.org/r/20221129010146.1026685-1-cuigaosheng1@huawei.com Signed-off-by: Michal Simek Signed-off-by: Sasha Levin --- drivers/soc/xilinx/xlnx_event_manager.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/soc/xilinx/xlnx_event_manager.c b/drivers/soc/xilinx/xlnx_event_manager.c index 2de082765bef..c76381899ef4 100644 --- a/drivers/soc/xilinx/xlnx_event_manager.c +++ b/drivers/soc/xilinx/xlnx_event_manager.c @@ -116,8 +116,10 @@ static int xlnx_add_cb_for_notify_event(const u32 node_id, const u32 event, cons INIT_LIST_HEAD(&eve_data->cb_list_head); cb_data = kmalloc(sizeof(*cb_data), GFP_KERNEL); - if (!cb_data) + if (!cb_data) { + kfree(eve_data); return -ENOMEM; + } cb_data->eve_cb = cb_fun; cb_data->agent_data = data; From 14b3742f34b13b970a4e7ba91884106ce6caab72 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 28 Nov 2022 10:15:09 +0100 Subject: [PATCH 005/201] f2fs: don't rely on F2FS_MAP_* in f2fs_iomap_begin [ Upstream commit 8d3c1fa3fa5eacfd14f5b018eddb6c1a91c57783 ] When testing with a mixed zoned / convention device combination, there are regular but not 100% reproducible failures in xfstests generic/113 where the __is_valid_data_blkaddr assert hits due to finding a hole. This seems to be because f2fs_map_blocks can set this flag on a hole when it was found in the extent cache. Rework f2fs_iomap_begin to just check the special block numbers directly. This has the added benefits of the WARN_ON showing which invalid block address we found, and being properly error out on delalloc blocks that are confusingly called unwritten but not actually suitable for direct I/O. Fixes: 1517c1a7a445 ("f2fs: implement iomap operations") Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin --- fs/f2fs/data.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 5f4519af9821..f92899bfcbd5 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -4138,20 +4138,24 @@ static int f2fs_iomap_begin(struct inode *inode, loff_t offset, loff_t length, */ map.m_len = fscrypt_limit_io_blocks(inode, map.m_lblk, map.m_len); - if (map.m_flags & (F2FS_MAP_MAPPED | F2FS_MAP_UNWRITTEN)) { - iomap->length = blks_to_bytes(inode, map.m_len); - if (map.m_flags & F2FS_MAP_MAPPED) { - iomap->type = IOMAP_MAPPED; - iomap->flags |= IOMAP_F_MERGED; - } else { - iomap->type = IOMAP_UNWRITTEN; - } - if (WARN_ON_ONCE(!__is_valid_data_blkaddr(map.m_pblk))) - return -EINVAL; + /* + * We should never see delalloc or compressed extents here based on + * prior flushing and checks. + */ + if (WARN_ON_ONCE(map.m_pblk == NEW_ADDR)) + return -EINVAL; + if (WARN_ON_ONCE(map.m_pblk == COMPRESS_ADDR)) + return -EINVAL; + if (map.m_pblk != NULL_ADDR) { + iomap->length = blks_to_bytes(inode, map.m_len); + iomap->type = IOMAP_MAPPED; + iomap->flags |= IOMAP_F_MERGED; iomap->bdev = map.m_bdev; iomap->addr = blks_to_bytes(inode, map.m_pblk); } else { + if (flags & IOMAP_WRITE) + return -ENOTBLK; iomap->length = blks_to_bytes(inode, next_pgofs) - iomap->offset; iomap->type = IOMAP_HOLE; From 4a229379a72e04842cec91a802b47c2c68f1cdc9 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Fri, 16 Dec 2022 23:50:00 +0800 Subject: [PATCH 006/201] f2fs: fix to avoid potential deadlock [ Upstream commit 5eaac835f27f2de6b73412d7c24e755733b49de0 ] There is a potential deadlock reported by syzbot as below: F2FS-fs (loop2): invalid crc value F2FS-fs (loop2): Found nat_bits in checkpoint F2FS-fs (loop2): Mounted with checkpoint version = 48b305e4 ====================================================== WARNING: possible circular locking dependency detected 6.1.0-rc8-syzkaller-33330-ga5541c0811a0 #0 Not tainted ------------------------------------------------------ syz-executor.2/32123 is trying to acquire lock: ffff0000c0e1a608 (&mm->mmap_lock){++++}-{3:3}, at: __might_fault+0x54/0xb4 mm/memory.c:5644 but task is already holding lock: ffff0001317c6088 (&sbi->sb_lock){++++}-{3:3}, at: f2fs_down_write fs/f2fs/f2fs.h:2205 [inline] ffff0001317c6088 (&sbi->sb_lock){++++}-{3:3}, at: f2fs_ioc_get_encryption_pwsalt fs/f2fs/file.c:2334 [inline] ffff0001317c6088 (&sbi->sb_lock){++++}-{3:3}, at: __f2fs_ioctl+0x1370/0x3318 fs/f2fs/file.c:4151 which lock already depends on the new lock. Chain exists of: &mm->mmap_lock --> &nm_i->nat_tree_lock --> &sbi->sb_lock Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&sbi->sb_lock); lock(&nm_i->nat_tree_lock); lock(&sbi->sb_lock); lock(&mm->mmap_lock); Let's try to avoid above deadlock condition by moving __might_fault() out of sbi->sb_lock coverage. Fixes: 95fa90c9e5a7 ("f2fs: support recording errors into superblock") Link: https://lore.kernel.org/linux-f2fs-devel/000000000000cd5fe305ef617fe2@google.com/T/#u Reported-by: syzbot+4793f6096d174c90b4f7@syzkaller.appspotmail.com Signed-off-by: Chao Yu Reviewed-by: Eric Biggers Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin --- fs/f2fs/file.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index f96bbfa8b399..a03c61bd7016 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -2326,6 +2326,7 @@ static int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg) { struct inode *inode = file_inode(filp); struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + u8 encrypt_pw_salt[16]; int err; if (!f2fs_sb_has_encrypt(sbi)) @@ -2350,12 +2351,14 @@ static int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg) goto out_err; } got_it: - if (copy_to_user((__u8 __user *)arg, sbi->raw_super->encrypt_pw_salt, - 16)) - err = -EFAULT; + memcpy(encrypt_pw_salt, sbi->raw_super->encrypt_pw_salt, 16); out_err: f2fs_up_write(&sbi->sb_lock); mnt_drop_write_file(filp); + + if (!err && copy_to_user((__u8 __user *)arg, encrypt_pw_salt, 16)) + err = -EFAULT; + return err; } From a8f63d747bf7c983882a5ea7456a5f84ad3acad5 Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Mon, 5 Dec 2022 12:06:42 +0400 Subject: [PATCH 007/201] objtool: Fix memory leak in create_static_call_sections() [ Upstream commit 3da73f102309fe29150e5c35acd20dd82063ff67 ] strdup() allocates memory for key_name. We need to release the memory in the following error paths. Add free() to avoid memory leak. Fixes: 1e7e47883830 ("x86/static_call: Add inline static call implementation for x86-64") Signed-off-by: Miaoqian Lin Signed-off-by: Ingo Molnar Link: https://lore.kernel.org/r/20221205080642.558583-1-linmq006@gmail.com Cc: Josh Poimboeuf Cc: Peter Zijlstra Signed-off-by: Sasha Levin --- tools/objtool/check.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 0c1b6acad141..730b49e255e4 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -668,6 +668,7 @@ static int create_static_call_sections(struct objtool_file *file) if (strncmp(key_name, STATIC_CALL_TRAMP_PREFIX_STR, STATIC_CALL_TRAMP_PREFIX_LEN)) { WARN("static_call: trampoline name malformed: %s", key_name); + free(key_name); return -1; } tmp = key_name + STATIC_CALL_TRAMP_PREFIX_LEN - STATIC_CALL_KEY_PREFIX_LEN; @@ -677,6 +678,7 @@ static int create_static_call_sections(struct objtool_file *file) if (!key_sym) { if (!opts.module) { WARN("static_call: can't find static_call_key symbol: %s", tmp); + free(key_name); return -1; } From e59c4d34f8ec800bb3cd1a3570379ed39f35474b Mon Sep 17 00:00:00 2001 From: Tinghan Shen Date: Wed, 12 Oct 2022 15:54:34 +0800 Subject: [PATCH 008/201] soc: mediatek: mtk-pm-domains: Allow mt8186 ADSP default power on [ Upstream commit 0d08c56d97a614f56d74f490d693faf8038db125 ] In the use case of configuring the access permissions of the ADSP core, the mt8186 SoC ADSP power will be switched on in the bootloader because the permission control registers are located in the ADSP subsys. Signed-off-by: Tinghan Shen Fixes: 88590cbc1703 ("soc: mediatek: pm-domains: Add support for mt8186") Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20221012075434.30009-1-tinghan.shen@mediatek.com Signed-off-by: Matthias Brugger Signed-off-by: Sasha Levin --- drivers/soc/mediatek/mt8186-pm-domains.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/soc/mediatek/mt8186-pm-domains.h b/drivers/soc/mediatek/mt8186-pm-domains.h index 108af61854a3..fce86f79c505 100644 --- a/drivers/soc/mediatek/mt8186-pm-domains.h +++ b/drivers/soc/mediatek/mt8186-pm-domains.h @@ -304,7 +304,6 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8186[] = { .ctl_offs = 0x9FC, .pwr_sta_offs = 0x16C, .pwr_sta2nd_offs = 0x170, - .caps = MTK_SCPD_KEEP_DEFAULT_OFF, }, [MT8186_POWER_DOMAIN_ADSP_INFRA] = { .name = "adsp_infra", @@ -312,7 +311,6 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8186[] = { .ctl_offs = 0x9F8, .pwr_sta_offs = 0x16C, .pwr_sta2nd_offs = 0x170, - .caps = MTK_SCPD_KEEP_DEFAULT_OFF, }, [MT8186_POWER_DOMAIN_ADSP_TOP] = { .name = "adsp_top", @@ -332,7 +330,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8186[] = { MT8186_TOP_AXI_PROT_EN_3_CLR, MT8186_TOP_AXI_PROT_EN_3_STA), }, - .caps = MTK_SCPD_SRAM_ISO | MTK_SCPD_KEEP_DEFAULT_OFF | MTK_SCPD_ACTIVE_WAKEUP, + .caps = MTK_SCPD_SRAM_ISO | MTK_SCPD_ACTIVE_WAKEUP, }, }; From fbb7c909634233fd94bc47c5fcc618945ad7e1f2 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 23 Nov 2022 15:41:17 +0100 Subject: [PATCH 009/201] memory: renesas-rpc-if: Split-off private data from struct rpcif [ Upstream commit 51de3fc9a84d8e99dd3f02536a623f9fb95d0c0a ] The rpcif structure is used as a common data structure, shared by the RPC-IF core driver and by the HyperBus and SPI child drivers. This poses several problems: - Most structure members describe private core driver state, which should not be accessible by the child drivers, - The structure's lifetime is controlled by the child drivers, complicating use by the core driver. Fix this by moving the private core driver state to its own structure, managed by the RPC-IF core driver, and store it in the core driver's private data field. This requires absorbing the child's platform device, as that was stored in the driver's private data field before. Fixes: ca7d8b980b67 ("memory: add Renesas RPC-IF driver") Signed-off-by: Geert Uytterhoeven Acked-by: Wolfram Sang Link: https://lore.kernel.org/r/09fbb6fa67d5a8cd48a08808c9afa2f6a499aa42.1669213027.git.geert+renesas@glider.be Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sasha Levin --- drivers/memory/renesas-rpc-if.c | 75 +++++++++++++++++++++++++-------- include/memory/renesas-rpc-if.h | 16 ------- 2 files changed, 57 insertions(+), 34 deletions(-) diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c index 61c288d40375..309c0b59f3a2 100644 --- a/drivers/memory/renesas-rpc-if.c +++ b/drivers/memory/renesas-rpc-if.c @@ -162,14 +162,36 @@ static const struct regmap_access_table rpcif_volatile_table = { .n_yes_ranges = ARRAY_SIZE(rpcif_volatile_ranges), }; +struct rpcif_priv { + struct device *dev; + void __iomem *base; + void __iomem *dirmap; + struct regmap *regmap; + struct reset_control *rstc; + struct platform_device *vdev; + size_t size; + enum rpcif_type type; + enum rpcif_data_dir dir; + u8 bus_size; + u8 xfer_size; + void *buffer; + u32 xferlen; + u32 smcr; + u32 smadr; + u32 command; /* DRCMR or SMCMR */ + u32 option; /* DROPR or SMOPR */ + u32 enable; /* DRENR or SMENR */ + u32 dummy; /* DRDMCR or SMDMCR */ + u32 ddr; /* DRDRENR or SMDRENR */ +}; /* * Custom accessor functions to ensure SM[RW]DR[01] are always accessed with - * proper width. Requires rpcif.xfer_size to be correctly set before! + * proper width. Requires rpcif_priv.xfer_size to be correctly set before! */ static int rpcif_reg_read(void *context, unsigned int reg, unsigned int *val) { - struct rpcif *rpc = context; + struct rpcif_priv *rpc = context; switch (reg) { case RPCIF_SMRDR0: @@ -205,7 +227,7 @@ static int rpcif_reg_read(void *context, unsigned int reg, unsigned int *val) static int rpcif_reg_write(void *context, unsigned int reg, unsigned int val) { - struct rpcif *rpc = context; + struct rpcif_priv *rpc = context; switch (reg) { case RPCIF_SMWDR0: @@ -252,13 +274,12 @@ static const struct regmap_config rpcif_regmap_config = { .volatile_table = &rpcif_volatile_table, }; -int rpcif_sw_init(struct rpcif *rpc, struct device *dev) +int rpcif_sw_init(struct rpcif *rpcif, struct device *dev) { struct platform_device *pdev = to_platform_device(dev); + struct rpcif_priv *rpc = dev_get_drvdata(dev); struct resource *res; - rpc->dev = dev; - rpc->base = devm_platform_ioremap_resource_byname(pdev, "regs"); if (IS_ERR(rpc->base)) return PTR_ERR(rpc->base); @@ -279,12 +300,17 @@ int rpcif_sw_init(struct rpcif *rpc, struct device *dev) rpc->type = (uintptr_t)of_device_get_match_data(dev); rpc->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); + if (IS_ERR(rpc->rstc)) + return PTR_ERR(rpc->rstc); - return PTR_ERR_OR_ZERO(rpc->rstc); + rpcif->dev = dev; + rpcif->dirmap = rpc->dirmap; + rpcif->size = rpc->size; + return 0; } EXPORT_SYMBOL(rpcif_sw_init); -static void rpcif_rzg2l_timing_adjust_sdr(struct rpcif *rpc) +static void rpcif_rzg2l_timing_adjust_sdr(struct rpcif_priv *rpc) { regmap_write(rpc->regmap, RPCIF_PHYWR, 0xa5390000); regmap_write(rpc->regmap, RPCIF_PHYADD, 0x80000000); @@ -298,8 +324,9 @@ static void rpcif_rzg2l_timing_adjust_sdr(struct rpcif *rpc) regmap_write(rpc->regmap, RPCIF_PHYADD, 0x80000032); } -int rpcif_hw_init(struct rpcif *rpc, bool hyperflash) +int rpcif_hw_init(struct rpcif *rpcif, bool hyperflash) { + struct rpcif_priv *rpc = dev_get_drvdata(rpcif->dev); u32 dummy; pm_runtime_get_sync(rpc->dev); @@ -360,7 +387,7 @@ int rpcif_hw_init(struct rpcif *rpc, bool hyperflash) } EXPORT_SYMBOL(rpcif_hw_init); -static int wait_msg_xfer_end(struct rpcif *rpc) +static int wait_msg_xfer_end(struct rpcif_priv *rpc) { u32 sts; @@ -369,7 +396,7 @@ static int wait_msg_xfer_end(struct rpcif *rpc) USEC_PER_SEC); } -static u8 rpcif_bits_set(struct rpcif *rpc, u32 nbytes) +static u8 rpcif_bits_set(struct rpcif_priv *rpc, u32 nbytes) { if (rpc->bus_size == 2) nbytes /= 2; @@ -382,9 +409,11 @@ static u8 rpcif_bit_size(u8 buswidth) return buswidth > 4 ? 2 : ilog2(buswidth); } -void rpcif_prepare(struct rpcif *rpc, const struct rpcif_op *op, u64 *offs, +void rpcif_prepare(struct rpcif *rpcif, const struct rpcif_op *op, u64 *offs, size_t *len) { + struct rpcif_priv *rpc = dev_get_drvdata(rpcif->dev); + rpc->smcr = 0; rpc->smadr = 0; rpc->enable = 0; @@ -468,8 +497,9 @@ void rpcif_prepare(struct rpcif *rpc, const struct rpcif_op *op, u64 *offs, } EXPORT_SYMBOL(rpcif_prepare); -int rpcif_manual_xfer(struct rpcif *rpc) +int rpcif_manual_xfer(struct rpcif *rpcif) { + struct rpcif_priv *rpc = dev_get_drvdata(rpcif->dev); u32 smenr, smcr, pos = 0, max = rpc->bus_size == 2 ? 8 : 4; int ret = 0; @@ -589,7 +619,7 @@ exit: err_out: if (reset_control_reset(rpc->rstc)) dev_err(rpc->dev, "Failed to reset HW\n"); - rpcif_hw_init(rpc, rpc->bus_size == 2); + rpcif_hw_init(rpcif, rpc->bus_size == 2); goto exit; } EXPORT_SYMBOL(rpcif_manual_xfer); @@ -636,8 +666,9 @@ static void memcpy_fromio_readw(void *to, } } -ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf) +ssize_t rpcif_dirmap_read(struct rpcif *rpcif, u64 offs, size_t len, void *buf) { + struct rpcif_priv *rpc = dev_get_drvdata(rpcif->dev); loff_t from = offs & (rpc->size - 1); size_t size = rpc->size - from; @@ -672,6 +703,7 @@ static int rpcif_probe(struct platform_device *pdev) { struct platform_device *vdev; struct device_node *flash; + struct rpcif_priv *rpc; const char *name; int ret; @@ -692,11 +724,18 @@ static int rpcif_probe(struct platform_device *pdev) } of_node_put(flash); + rpc = devm_kzalloc(&pdev->dev, sizeof(*rpc), GFP_KERNEL); + if (!rpc) + return -ENOMEM; + vdev = platform_device_alloc(name, pdev->id); if (!vdev) return -ENOMEM; vdev->dev.parent = &pdev->dev; - platform_set_drvdata(pdev, vdev); + + rpc->dev = &pdev->dev; + rpc->vdev = vdev; + platform_set_drvdata(pdev, rpc); ret = platform_device_add(vdev); if (ret) { @@ -709,9 +748,9 @@ static int rpcif_probe(struct platform_device *pdev) static int rpcif_remove(struct platform_device *pdev) { - struct platform_device *vdev = platform_get_drvdata(pdev); + struct rpcif_priv *rpc = platform_get_drvdata(pdev); - platform_device_unregister(vdev); + platform_device_unregister(rpc->vdev); return 0; } diff --git a/include/memory/renesas-rpc-if.h b/include/memory/renesas-rpc-if.h index 9c0ad64b8d29..ddf94356752d 100644 --- a/include/memory/renesas-rpc-if.h +++ b/include/memory/renesas-rpc-if.h @@ -64,24 +64,8 @@ enum rpcif_type { struct rpcif { struct device *dev; - void __iomem *base; void __iomem *dirmap; - struct regmap *regmap; - struct reset_control *rstc; size_t size; - enum rpcif_type type; - enum rpcif_data_dir dir; - u8 bus_size; - u8 xfer_size; - void *buffer; - u32 xferlen; - u32 smcr; - u32 smadr; - u32 command; /* DRCMR or SMCMR */ - u32 option; /* DROPR or SMOPR */ - u32 enable; /* DRENR or SMENR */ - u32 dummy; /* DRDMCR or SMDMCR */ - u32 ddr; /* DRDRENR or SMDRENR */ }; int rpcif_sw_init(struct rpcif *rpc, struct device *dev); From 2c82bf3f1762379398c6ec980e42f285a07f09a1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 23 Nov 2022 15:41:18 +0100 Subject: [PATCH 010/201] memory: renesas-rpc-if: Move resource acquisition to .probe() [ Upstream commit 8b3580df15f53045fda3ffae53f74575c96aa77e ] While the acquired resources are tied to the lifetime of the RPC-IF core device (through the use of managed resource functions), the actual resource acquisition is triggered from the HyperBus and SPI child drivers. Due to this mismatch, unbinding and rebinding the child drivers manually fails with -EBUSY: # echo rpc-if-hyperflash > /sys/bus/platform/drivers/rpc-if-hyperflash/unbind # echo rpc-if-hyperflash > /sys/bus/platform/drivers/rpc-if-hyperflash/bind rpc-if ee200000.spi: can't request region for resource [mem 0xee200000-0xee2001ff] rpc-if-hyperflash: probe of rpc-if-hyperflash failed with error -16 The same is true for rpc-if-spi. Fix this by moving all resource acquisition to the core driver's probe routine. Fixes: ca7d8b980b67 ("memory: add Renesas RPC-IF driver") Signed-off-by: Geert Uytterhoeven Acked-by: Wolfram Sang Link: https://lore.kernel.org/r/c1012ef1de799e08a70817ab7313794e2d8d7bfb.1669213027.git.geert+renesas@glider.be Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sasha Levin --- drivers/memory/renesas-rpc-if.c | 49 ++++++++++++++++----------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c index 309c0b59f3a2..7343dbb79c9f 100644 --- a/drivers/memory/renesas-rpc-if.c +++ b/drivers/memory/renesas-rpc-if.c @@ -276,32 +276,7 @@ static const struct regmap_config rpcif_regmap_config = { int rpcif_sw_init(struct rpcif *rpcif, struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); struct rpcif_priv *rpc = dev_get_drvdata(dev); - struct resource *res; - - rpc->base = devm_platform_ioremap_resource_byname(pdev, "regs"); - if (IS_ERR(rpc->base)) - return PTR_ERR(rpc->base); - - rpc->regmap = devm_regmap_init(&pdev->dev, NULL, rpc, &rpcif_regmap_config); - if (IS_ERR(rpc->regmap)) { - dev_err(&pdev->dev, - "failed to init regmap for rpcif, error %ld\n", - PTR_ERR(rpc->regmap)); - return PTR_ERR(rpc->regmap); - } - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dirmap"); - rpc->dirmap = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(rpc->dirmap)) - return PTR_ERR(rpc->dirmap); - rpc->size = resource_size(res); - - rpc->type = (uintptr_t)of_device_get_match_data(dev); - rpc->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); - if (IS_ERR(rpc->rstc)) - return PTR_ERR(rpc->rstc); rpcif->dev = dev; rpcif->dirmap = rpc->dirmap; @@ -701,9 +676,11 @@ EXPORT_SYMBOL(rpcif_dirmap_read); static int rpcif_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct platform_device *vdev; struct device_node *flash; struct rpcif_priv *rpc; + struct resource *res; const char *name; int ret; @@ -728,6 +705,28 @@ static int rpcif_probe(struct platform_device *pdev) if (!rpc) return -ENOMEM; + rpc->base = devm_platform_ioremap_resource_byname(pdev, "regs"); + if (IS_ERR(rpc->base)) + return PTR_ERR(rpc->base); + + rpc->regmap = devm_regmap_init(dev, NULL, rpc, &rpcif_regmap_config); + if (IS_ERR(rpc->regmap)) { + dev_err(dev, "failed to init regmap for rpcif, error %ld\n", + PTR_ERR(rpc->regmap)); + return PTR_ERR(rpc->regmap); + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dirmap"); + rpc->dirmap = devm_ioremap_resource(dev, res); + if (IS_ERR(rpc->dirmap)) + return PTR_ERR(rpc->dirmap); + rpc->size = resource_size(res); + + rpc->type = (uintptr_t)of_device_get_match_data(dev); + rpc->rstc = devm_reset_control_get_exclusive(dev, NULL); + if (IS_ERR(rpc->rstc)) + return PTR_ERR(rpc->rstc); + vdev = platform_device_alloc(name, pdev->id); if (!vdev) return -ENOMEM; From 6b99ebd30d65ee5ab8e8dd1d378550911eff5e4f Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Tue, 20 Dec 2022 22:35:59 +0100 Subject: [PATCH 011/201] soc: mediatek: mtk-svs: Enable the IRQ later [ Upstream commit b74952aba6c3f47e7f2c5165abaeefa44c377140 ] If the system does not come from reset (like when is booted via kexec()), the peripheral might triger an IRQ before the data structures are initialised. Fixes: [ 0.227710] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000f08 [ 0.227913] Call trace: [ 0.227918] svs_isr+0x8c/0x538 Signed-off-by: Ricardo Ribalda Link: https://lore.kernel.org/r/20221127-mtk-svs-v2-0-145b07663ea8@chromium.org Signed-off-by: Matthias Brugger Signed-off-by: Sasha Levin --- drivers/soc/mediatek/mtk-svs.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c index 0469c9dfeb04..75b2f534aa9d 100644 --- a/drivers/soc/mediatek/mtk-svs.c +++ b/drivers/soc/mediatek/mtk-svs.c @@ -2385,14 +2385,6 @@ static int svs_probe(struct platform_device *pdev) goto svs_probe_free_resource; } - ret = devm_request_threaded_irq(svsp->dev, svsp_irq, NULL, svs_isr, - IRQF_ONESHOT, svsp->name, svsp); - if (ret) { - dev_err(svsp->dev, "register irq(%d) failed: %d\n", - svsp_irq, ret); - goto svs_probe_free_resource; - } - svsp->main_clk = devm_clk_get(svsp->dev, "main"); if (IS_ERR(svsp->main_clk)) { dev_err(svsp->dev, "failed to get clock: %ld\n", @@ -2414,6 +2406,14 @@ static int svs_probe(struct platform_device *pdev) goto svs_probe_clk_disable; } + ret = devm_request_threaded_irq(svsp->dev, svsp_irq, NULL, svs_isr, + IRQF_ONESHOT, svsp->name, svsp); + if (ret) { + dev_err(svsp->dev, "register irq(%d) failed: %d\n", + svsp_irq, ret); + goto svs_probe_iounmap; + } + ret = svs_start(svsp); if (ret) { dev_err(svsp->dev, "svs start fail: %d\n", ret); From 094ffaf50bb94fc91141aa85f7fcb33df723234b Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Wed, 9 Nov 2022 12:37:24 +0100 Subject: [PATCH 012/201] pwm: sifive: Always let the first pwm_apply_state succeed [ Upstream commit 334c7b13d38321e47d1a51dba0bef9f4c403ec75 ] Commit 2cfe9bbec56ea579135cdd92409fff371841904f added support for the RGB and green PWM controlled LEDs on the HiFive Unmatched board managed by the leds-pwm-multicolor and leds-pwm drivers respectively. All three colours of the RGB LED and the green LED run from different lines of the same PWM, but with the same period so this works fine when the LED drivers are loaded one after the other. Unfortunately it does expose a race in the PWM driver when both LED drivers are loaded at roughly the same time. Here is an example: | Thread A | Thread B | | led_pwm_mc_probe | led_pwm_probe | | devm_fwnode_pwm_get | | | pwm_sifive_request | | | ddata->user_count++ | | | | devm_fwnode_pwm_get | | | pwm_sifive_request | | | ddata->user_count++ | | ... | ... | | pwm_state_apply | pwm_state_apply | | pwm_sifive_apply | pwm_sifive_apply | Now both calls to pwm_sifive_apply will see that ddata->approx_period, initially 0, is different from the requested period and the clock needs to be updated. But since ddata->user_count >= 2 both calls will fail with -EBUSY, which will then cause both LED drivers to fail to probe. Fix it by letting the first call to pwm_sifive_apply update the clock even when ddata->user_count != 1. Fixes: 9e37a53eb051 ("pwm: sifive: Add a driver for SiFive SoC PWM") Signed-off-by: Emil Renner Berthing Signed-off-by: Thierry Reding Signed-off-by: Sasha Levin --- drivers/pwm/pwm-sifive.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c index bb7239313401..89d53a0f91e6 100644 --- a/drivers/pwm/pwm-sifive.c +++ b/drivers/pwm/pwm-sifive.c @@ -159,7 +159,13 @@ static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm, mutex_lock(&ddata->lock); if (state->period != ddata->approx_period) { - if (ddata->user_count != 1) { + /* + * Don't let a 2nd user change the period underneath the 1st user. + * However if ddate->approx_period == 0 this is the first time we set + * any period, so let whoever gets here first set the period so other + * users who agree on the period won't fail. + */ + if (ddata->user_count != 1 && ddata->approx_period) { mutex_unlock(&ddata->lock); return -EBUSY; } From 9a0af7cb1c0b7b018ca308fac56418faabd722dd Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Wed, 23 Nov 2022 14:36:52 +0100 Subject: [PATCH 013/201] pwm: stm32-lp: fix the check on arr and cmp registers update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 3066bc2d58be31275afb51a589668f265e419c37 ] The ARR (auto reload register) and CMP (compare) registers are successively written. The status bits to check the update of these registers are polled together with regmap_read_poll_timeout(). The condition to end the loop may become true, even if one of the register isn't correctly updated. So ensure both status bits are set before clearing them. Fixes: e70a540b4e02 ("pwm: Add STM32 LPTimer PWM driver") Signed-off-by: Fabrice Gasnier Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding Signed-off-by: Sasha Levin --- drivers/pwm/pwm-stm32-lp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c index 3115abb3f52a..61a1c87cd501 100644 --- a/drivers/pwm/pwm-stm32-lp.c +++ b/drivers/pwm/pwm-stm32-lp.c @@ -127,7 +127,7 @@ static int stm32_pwm_lp_apply(struct pwm_chip *chip, struct pwm_device *pwm, /* ensure CMP & ARR registers are properly written */ ret = regmap_read_poll_timeout(priv->regmap, STM32_LPTIM_ISR, val, - (val & STM32_LPTIM_CMPOK_ARROK), + (val & STM32_LPTIM_CMPOK_ARROK) == STM32_LPTIM_CMPOK_ARROK, 100, 1000); if (ret) { dev_err(priv->chip.dev, "ARR/CMP registers write issue\n"); From 9ad51915f4b368eef8f4cbd3a0b6367d4504c245 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 9 Jan 2023 11:44:49 +0800 Subject: [PATCH 014/201] f2fs: introduce trace_f2fs_replace_atomic_write_block [ Upstream commit 2f3a9ae990a7881c9a57a073bb52ebe34fdc3160 ] Commit 3db1de0e582c ("f2fs: change the current atomic write way") removed old tracepoints, but it missed to add new one, this patch fixes to introduce trace_f2fs_replace_atomic_write_block to trace atomic_write commit flow. Fixes: 3db1de0e582c ("f2fs: change the current atomic write way") Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin --- fs/f2fs/segment.c | 3 +++ include/trace/events/f2fs.h | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index c1d0713666ee..af9a3b7996b4 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -250,6 +250,9 @@ retry: } f2fs_put_dnode(&dn); + + trace_f2fs_replace_atomic_write_block(inode, F2FS_I(inode)->cow_inode, + index, *old_addr, new_addr, recover); return 0; } diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index ff57e7f9914c..e57f867191ef 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -1286,6 +1286,43 @@ DEFINE_EVENT(f2fs__page, f2fs_vm_page_mkwrite, TP_ARGS(page, type) ); +TRACE_EVENT(f2fs_replace_atomic_write_block, + + TP_PROTO(struct inode *inode, struct inode *cow_inode, pgoff_t index, + block_t old_addr, block_t new_addr, bool recovery), + + TP_ARGS(inode, cow_inode, index, old_addr, new_addr, recovery), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __field(ino_t, cow_ino) + __field(pgoff_t, index) + __field(block_t, old_addr) + __field(block_t, new_addr) + __field(bool, recovery) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->cow_ino = cow_inode->i_ino; + __entry->index = index; + __entry->old_addr = old_addr; + __entry->new_addr = new_addr; + __entry->recovery = recovery; + ), + + TP_printk("dev = (%d,%d), ino = %lu, cow_ino = %lu, index = %lu, " + "old_addr = 0x%llx, new_addr = 0x%llx, recovery = %d", + show_dev_ino(__entry), + __entry->cow_ino, + (unsigned long)__entry->index, + (unsigned long long)__entry->old_addr, + (unsigned long long)__entry->new_addr, + __entry->recovery) +); + TRACE_EVENT(f2fs_filemap_fault, TP_PROTO(struct inode *inode, pgoff_t index, unsigned long ret), From 4bc488c5ca0e2d3c4a419572faf636e4d9a8dfc9 Mon Sep 17 00:00:00 2001 From: Daeho Jeong Date: Mon, 31 Oct 2022 12:24:15 -0700 Subject: [PATCH 015/201] f2fs: correct i_size change for atomic writes [ Upstream commit 4d8d45df2252980f800c1b2fde941a103a18a70e ] We need to make sure i_size doesn't change until atomic write commit is successful and restore it when commit is failed. Signed-off-by: Daeho Jeong Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim Stable-dep-of: 0e8d040bfa4c ("f2fs: clear atomic_write_task in f2fs_abort_atomic_write()") Signed-off-by: Sasha Levin --- fs/f2fs/f2fs.h | 8 ++++++++ fs/f2fs/file.c | 18 +++++++++++------- fs/f2fs/inode.c | 5 ++++- fs/f2fs/segment.c | 14 ++++++++++---- 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 8b9f0b3c7723..87664c309b3c 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -764,6 +764,7 @@ enum { FI_COMPRESS_RELEASED, /* compressed blocks were released */ FI_ALIGNED_WRITE, /* enable aligned write */ FI_COW_FILE, /* indicate COW file */ + FI_ATOMIC_COMMITTED, /* indicate atomic commit completed except disk sync */ FI_MAX, /* max flag, never be used */ }; @@ -822,6 +823,7 @@ struct f2fs_inode_info { unsigned int i_cluster_size; /* cluster size */ unsigned int atomic_write_cnt; + loff_t original_i_size; /* original i_size before atomic write */ }; static inline void get_extent_info(struct extent_info *ext, @@ -3072,6 +3074,8 @@ static inline void f2fs_i_blocks_write(struct inode *inode, set_inode_flag(inode, FI_AUTO_RECOVER); } +static inline bool f2fs_is_atomic_file(struct inode *inode); + static inline void f2fs_i_size_write(struct inode *inode, loff_t i_size) { bool clean = !is_inode_flag_set(inode, FI_DIRTY_INODE); @@ -3081,6 +3085,10 @@ static inline void f2fs_i_size_write(struct inode *inode, loff_t i_size) return; i_size_write(inode, i_size); + + if (f2fs_is_atomic_file(inode)) + return; + f2fs_mark_inode_dirty_sync(inode, true); if (clean || recover) set_inode_flag(inode, FI_AUTO_RECOVER); diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index a03c61bd7016..7bb0c05e943c 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -2041,6 +2041,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) struct f2fs_inode_info *fi = F2FS_I(inode); struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct inode *pinode; + loff_t isize; int ret; if (!inode_owner_or_capable(mnt_userns, inode)) @@ -2099,7 +2100,12 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) f2fs_up_write(&fi->i_gc_rwsem[WRITE]); goto out; } - f2fs_i_size_write(fi->cow_inode, i_size_read(inode)); + + f2fs_write_inode(inode, NULL); + + isize = i_size_read(inode); + fi->original_i_size = isize; + f2fs_i_size_write(fi->cow_inode, isize); stat_inc_atomic_inode(inode); @@ -2137,16 +2143,14 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp) if (f2fs_is_atomic_file(inode)) { ret = f2fs_commit_atomic_write(inode); - if (ret) - goto unlock_out; - - ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 0, true); if (!ret) - f2fs_abort_atomic_write(inode, false); + ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 0, true); + + f2fs_abort_atomic_write(inode, ret); } else { ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 1, false); } -unlock_out: + inode_unlock(inode); mnt_drop_write_file(filp); return ret; diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 5d6fd824f74f..e8413b080e0a 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -621,9 +621,12 @@ void f2fs_update_inode(struct inode *inode, struct page *node_page) ri->i_uid = cpu_to_le32(i_uid_read(inode)); ri->i_gid = cpu_to_le32(i_gid_read(inode)); ri->i_links = cpu_to_le32(inode->i_nlink); - ri->i_size = cpu_to_le64(i_size_read(inode)); ri->i_blocks = cpu_to_le64(SECTOR_TO_BLOCK(inode->i_blocks) + 1); + if (!f2fs_is_atomic_file(inode) || + is_inode_flag_set(inode, FI_ATOMIC_COMMITTED)) + ri->i_size = cpu_to_le64(i_size_read(inode)); + if (et) { read_lock(&et->lock); set_raw_extent(&et->largest, &ri->i_ext); diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index af9a3b7996b4..60d79e427f98 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -192,14 +192,18 @@ void f2fs_abort_atomic_write(struct inode *inode, bool clean) if (!f2fs_is_atomic_file(inode)) return; - if (clean) - truncate_inode_pages_final(inode->i_mapping); clear_inode_flag(fi->cow_inode, FI_COW_FILE); iput(fi->cow_inode); fi->cow_inode = NULL; release_atomic_write_cnt(inode); + clear_inode_flag(inode, FI_ATOMIC_COMMITTED); clear_inode_flag(inode, FI_ATOMIC_FILE); stat_dec_atomic_inode(inode); + + if (clean) { + truncate_inode_pages_final(inode->i_mapping); + f2fs_i_size_write(inode, fi->original_i_size); + } } static int __replace_atomic_write_block(struct inode *inode, pgoff_t index, @@ -338,10 +342,12 @@ next: } out: - if (ret) + if (ret) { sbi->revoked_atomic_block += fi->atomic_write_cnt; - else + } else { sbi->committed_atomic_block += fi->atomic_write_cnt; + set_inode_flag(inode, FI_ATOMIC_COMMITTED); + } __complete_revoke_list(inode, &revoke_list, ret ? true : false); From 0b65ff13f943a9372f782cf75451c78d435e4388 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 9 Jan 2023 11:44:50 +0800 Subject: [PATCH 016/201] f2fs: clear atomic_write_task in f2fs_abort_atomic_write() [ Upstream commit 0e8d040bfa4c476d7d2a23119527c744c7de13cd ] Otherwise, last .atomic_write_task will be remained in structure f2fs_inode_info, resulting in aborting atomic_write accidentally in race case. Meanwhile, clear original_i_size as well. Fixes: 7a10f0177e11 ("f2fs: don't give partially written atomic data from process crash") Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin --- fs/f2fs/segment.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 60d79e427f98..63c689409979 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -200,9 +200,12 @@ void f2fs_abort_atomic_write(struct inode *inode, bool clean) clear_inode_flag(inode, FI_ATOMIC_FILE); stat_dec_atomic_inode(inode); + F2FS_I(inode)->atomic_write_task = NULL; + if (clean) { truncate_inode_pages_final(inode->i_mapping); f2fs_i_size_write(inode, fi->original_i_size); + fi->original_i_size = 0; } } From e05aa300fb6979b3f063f83259b9d5166f877dc1 Mon Sep 17 00:00:00 2001 From: Roger Lu Date: Wed, 11 Jan 2023 15:45:15 +0800 Subject: [PATCH 017/201] soc: mediatek: mtk-svs: restore default voltages when svs_init02() fail [ Upstream commit a0674cd237fc24b08c7dcb4f8e48df3ee769293a ] If svs init02 fail, it means we cannot rely on svs bank voltages anymore. We need to disable svs function and restore DVFS opp voltages back to the default voltages for making sure we have enough DVFS voltages. Fixes: 681a02e95000 ("soc: mediatek: SVS: introduce MTK SVS engine") Fixes: 0bbb09b2af9d ("soc: mediatek: SVS: add mt8192 SVS GPU driver") Signed-off-by: Roger Lu Link: https://lore.kernel.org/r/20230111074528.29354-2-roger.lu@mediatek.com Signed-off-by: Matthias Brugger Signed-off-by: Sasha Levin --- drivers/soc/mediatek/mtk-svs.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c index 75b2f534aa9d..9859e6cf6b8f 100644 --- a/drivers/soc/mediatek/mtk-svs.c +++ b/drivers/soc/mediatek/mtk-svs.c @@ -1461,6 +1461,7 @@ static int svs_init02(struct svs_platform *svsp) { struct svs_bank *svsb; unsigned long flags, time_left; + int ret; u32 idx; for (idx = 0; idx < svsp->bank_max; idx++) { @@ -1479,7 +1480,8 @@ static int svs_init02(struct svs_platform *svsp) msecs_to_jiffies(5000)); if (!time_left) { dev_err(svsb->dev, "init02 completion timeout\n"); - return -EBUSY; + ret = -EBUSY; + goto out_of_init02; } } @@ -1497,12 +1499,30 @@ static int svs_init02(struct svs_platform *svsp) if (svsb->type == SVSB_HIGH || svsb->type == SVSB_LOW) { if (svs_sync_bank_volts_from_opp(svsb)) { dev_err(svsb->dev, "sync volt fail\n"); - return -EPERM; + ret = -EPERM; + goto out_of_init02; } } } return 0; + +out_of_init02: + for (idx = 0; idx < svsp->bank_max; idx++) { + svsb = &svsp->banks[idx]; + + spin_lock_irqsave(&svs_lock, flags); + svsp->pbank = svsb; + svs_switch_bank(svsp); + svs_writel_relaxed(svsp, SVSB_PTPEN_OFF, SVSEN); + svs_writel_relaxed(svsp, SVSB_INTSTS_VAL_CLEAN, INTSTS); + spin_unlock_irqrestore(&svs_lock, flags); + + svsb->phase = SVSB_PHASE_ERROR; + svs_adjust_pm_opp_volts(svsb); + } + + return ret; } static void svs_mon_mode(struct svs_platform *svsp) From 8fc4291f8de2408d019f8bfd46c94426b4684f3e Mon Sep 17 00:00:00 2001 From: Roger Lu Date: Wed, 11 Jan 2023 15:45:16 +0800 Subject: [PATCH 018/201] soc: mediatek: mtk-svs: reset svs when svs_resume() fail [ Upstream commit f4f8ad204a15d57c1a3e8ea7eca62157b44cbf59 ] Add svs reset when svs_resume() fail. Fixes: a825d72f74a3 ("soc: mediatek: fix missing clk_disable_unprepare() on err in svs_resume()") Signed-off-by: Roger Lu Link: https://lore.kernel.org/r/20230111074528.29354-3-roger.lu@mediatek.com Signed-off-by: Matthias Brugger Signed-off-by: Sasha Levin --- drivers/soc/mediatek/mtk-svs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c index 9859e6cf6b8f..e0b8aa75c84b 100644 --- a/drivers/soc/mediatek/mtk-svs.c +++ b/drivers/soc/mediatek/mtk-svs.c @@ -1614,12 +1614,16 @@ static int svs_resume(struct device *dev) ret = svs_init02(svsp); if (ret) - goto out_of_resume; + goto svs_resume_reset_assert; svs_mon_mode(svsp); return 0; +svs_resume_reset_assert: + dev_err(svsp->dev, "assert reset: %d\n", + reset_control_assert(svsp->rst)); + out_of_resume: clk_disable_unprepare(svsp->main_clk); return ret; From 125f898095010ff46512924ad09a90cd3a5ab2f8 Mon Sep 17 00:00:00 2001 From: Shang XiaoJing Date: Wed, 11 Jan 2023 15:45:18 +0800 Subject: [PATCH 019/201] soc: mediatek: mtk-svs: Use pm_runtime_resume_and_get() in svs_init01() [ Upstream commit 37fa2aff8fe490771f2229b0f2fcd15796b1bfca ] svs_init01() calls pm_runtime_get_sync() and added fail path as svs_init01_finish to put usage_counter. However, pm_runtime_get_sync() will increment usage_counter even it failed. Fix it by replacing it with pm_runtime_resume_and_get() to keep usage counter balanced. Fixes: 681a02e95000 ("soc: mediatek: SVS: introduce MTK SVS engine") Signed-off-by: Shang XiaoJing Signed-off-by: Roger Lu Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230111074528.29354-5-roger.lu@mediatek.com Signed-off-by: Matthias Brugger Signed-off-by: Sasha Levin --- drivers/soc/mediatek/mtk-svs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c index e0b8aa75c84b..00526fd37d7b 100644 --- a/drivers/soc/mediatek/mtk-svs.c +++ b/drivers/soc/mediatek/mtk-svs.c @@ -1324,7 +1324,7 @@ static int svs_init01(struct svs_platform *svsp) svsb->pm_runtime_enabled_count++; } - ret = pm_runtime_get_sync(svsb->opp_dev); + ret = pm_runtime_resume_and_get(svsb->opp_dev); if (ret < 0) { dev_err(svsb->dev, "mtcmos on fail: %d\n", ret); goto svs_init01_resume_cpuidle; From 05006a1521d8b5d4f87919942bf1180070cbc4ff Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Mon, 21 Nov 2022 12:21:32 +0100 Subject: [PATCH 020/201] fs: f2fs: initialize fsdata in pagecache_write() [ Upstream commit b1b9896718bc1a212dc288ad66a5fa2fef11353d ] When aops->write_begin() does not initialize fsdata, KMSAN may report an error passing the latter to aops->write_end(). Fix this by unconditionally initializing fsdata. Suggested-by: Eric Biggers Fixes: 95ae251fe828 ("f2fs: add fs-verity support") Signed-off-by: Alexander Potapenko Reviewed-by: Eric Biggers Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin --- fs/f2fs/verity.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/f2fs/verity.c b/fs/f2fs/verity.c index c352fff88a5e..3f4f3295f1c6 100644 --- a/fs/f2fs/verity.c +++ b/fs/f2fs/verity.c @@ -81,7 +81,7 @@ static int pagecache_write(struct inode *inode, const void *buf, size_t count, size_t n = min_t(size_t, count, PAGE_SIZE - offset_in_page(pos)); struct page *page; - void *fsdata; + void *fsdata = NULL; int res; res = aops->write_begin(NULL, mapping, pos, n, &page, &fsdata); From e11707d5f86fe1b507b1c2d70258df7c2661454e Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 23 Jan 2023 17:46:01 +0800 Subject: [PATCH 021/201] f2fs: allow set compression option of files without blocks [ Upstream commit e6261beb0c629403dc58997294dd521bd23664af ] Files created by truncate have a size but no blocks, so they can be allowed to set compression option. Fixes: e1e8debec656 ("f2fs: add F2FS_IOC_SET_COMPRESS_OPTION ioctl") Signed-off-by: Yangtao Li Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin --- fs/f2fs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 7bb0c05e943c..88eecd7149cd 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -3937,7 +3937,7 @@ static int f2fs_ioc_set_compress_option(struct file *filp, unsigned long arg) goto out; } - if (inode->i_size != 0) { + if (F2FS_HAS_BLOCKS(inode)) { ret = -EFBIG; goto out; } From 14e8bd4cfae3ffc921c64130777cdd1c7a2267c3 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 9 Jan 2023 11:44:51 +0800 Subject: [PATCH 022/201] f2fs: fix to abort atomic write only during do_exist() [ Upstream commit ae267fc1cfe9f941afcb90dc963ee6448dae73cf ] Commit 7a10f0177e11 ("f2fs: don't give partially written atomic data from process crash") attempted to drop atomic write data after process crash, however, f2fs_abort_atomic_write() may be called from noncrash case, fix it by adding missed PF_EXITING check condition f2fs_file_flush(). - application crashs - do_exit - exit_signals -- sets PF_EXITING - exit_files - put_files_struct - close_files - filp_close - flush (f2fs_file_flush) - check atomic_write_task && PF_EXITING - f2fs_abort_atomic_write Fixes: 7a10f0177e11 ("f2fs: don't give partially written atomic data from process crash") Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin --- fs/f2fs/file.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 88eecd7149cd..8a576c004b72 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1879,7 +1879,8 @@ static int f2fs_file_flush(struct file *file, fl_owner_t id) * until all the writers close its file. Since this should be done * before dropping file lock, it needs to do in ->flush. */ - if (F2FS_I(inode)->atomic_write_task == current) + if (F2FS_I(inode)->atomic_write_task == current && + (current->flags & PF_EXITING)) f2fs_abort_atomic_write(inode, true); return 0; } From c8583b4655aab44a9796b5c4a681ddcc6fe2f0d0 Mon Sep 17 00:00:00 2001 From: Xiang Yang Date: Tue, 15 Nov 2022 15:32:25 +0800 Subject: [PATCH 023/201] um: vector: Fix memory leak in vector_config [ Upstream commit 8f88c73afe481f93d40801596927e8c0047b6d96 ] If the return value of the uml_parse_vector_ifspec function is NULL, we should call kfree(params) to prevent memory leak. Fixes: 49da7e64f33e ("High Performance UML Vector Network Driver") Signed-off-by: Xiang Yang Acked-By: Anton Ivanov Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- arch/um/drivers/vector_kern.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/um/drivers/vector_kern.c b/arch/um/drivers/vector_kern.c index ded7c47d2fbe..131b7cb29576 100644 --- a/arch/um/drivers/vector_kern.c +++ b/arch/um/drivers/vector_kern.c @@ -767,6 +767,7 @@ static int vector_config(char *str, char **error_out) if (parsed == NULL) { *error_out = "vector_config failed to parse parameters"; + kfree(params); return -EINVAL; } From 61aeba0e4b4124cfe3c5427feaf29c626dfa89e5 Mon Sep 17 00:00:00 2001 From: George Kennedy Date: Tue, 15 Nov 2022 10:14:44 -0500 Subject: [PATCH 024/201] ubi: ensure that VID header offset + VID header size <= alloc, size [ Upstream commit 1b42b1a36fc946f0d7088425b90d491b4257ca3e ] Ensure that the VID header offset + VID header size does not exceed the allocated area to avoid slab OOB. BUG: KASAN: slab-out-of-bounds in crc32_body lib/crc32.c:111 [inline] BUG: KASAN: slab-out-of-bounds in crc32_le_generic lib/crc32.c:179 [inline] BUG: KASAN: slab-out-of-bounds in crc32_le_base+0x58c/0x626 lib/crc32.c:197 Read of size 4 at addr ffff88802bb36f00 by task syz-executor136/1555 CPU: 2 PID: 1555 Comm: syz-executor136 Tainted: G W 6.0.0-1868 #1 Hardware name: Red Hat KVM, BIOS 1.13.0-2.module+el8.3.0+7860+a7792d29 04/01/2014 Call Trace: __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0x85/0xad lib/dump_stack.c:106 print_address_description mm/kasan/report.c:317 [inline] print_report.cold.13+0xb6/0x6bb mm/kasan/report.c:433 kasan_report+0xa7/0x11b mm/kasan/report.c:495 crc32_body lib/crc32.c:111 [inline] crc32_le_generic lib/crc32.c:179 [inline] crc32_le_base+0x58c/0x626 lib/crc32.c:197 ubi_io_write_vid_hdr+0x1b7/0x472 drivers/mtd/ubi/io.c:1067 create_vtbl+0x4d5/0x9c4 drivers/mtd/ubi/vtbl.c:317 create_empty_lvol drivers/mtd/ubi/vtbl.c:500 [inline] ubi_read_volume_table+0x67b/0x288a drivers/mtd/ubi/vtbl.c:812 ubi_attach+0xf34/0x1603 drivers/mtd/ubi/attach.c:1601 ubi_attach_mtd_dev+0x6f3/0x185e drivers/mtd/ubi/build.c:965 ctrl_cdev_ioctl+0x2db/0x347 drivers/mtd/ubi/cdev.c:1043 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:870 [inline] __se_sys_ioctl fs/ioctl.c:856 [inline] __x64_sys_ioctl+0x193/0x213 fs/ioctl.c:856 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x3e/0x86 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0x0 RIP: 0033:0x7f96d5cf753d Code: RSP: 002b:00007fffd72206f8 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f96d5cf753d RDX: 0000000020000080 RSI: 0000000040186f40 RDI: 0000000000000003 RBP: 0000000000400cd0 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000400be0 R13: 00007fffd72207e0 R14: 0000000000000000 R15: 0000000000000000 Allocated by task 1555: kasan_save_stack+0x20/0x3d mm/kasan/common.c:38 kasan_set_track mm/kasan/common.c:45 [inline] set_alloc_info mm/kasan/common.c:437 [inline] ____kasan_kmalloc mm/kasan/common.c:516 [inline] __kasan_kmalloc+0x88/0xa3 mm/kasan/common.c:525 kasan_kmalloc include/linux/kasan.h:234 [inline] __kmalloc+0x138/0x257 mm/slub.c:4429 kmalloc include/linux/slab.h:605 [inline] ubi_alloc_vid_buf drivers/mtd/ubi/ubi.h:1093 [inline] create_vtbl+0xcc/0x9c4 drivers/mtd/ubi/vtbl.c:295 create_empty_lvol drivers/mtd/ubi/vtbl.c:500 [inline] ubi_read_volume_table+0x67b/0x288a drivers/mtd/ubi/vtbl.c:812 ubi_attach+0xf34/0x1603 drivers/mtd/ubi/attach.c:1601 ubi_attach_mtd_dev+0x6f3/0x185e drivers/mtd/ubi/build.c:965 ctrl_cdev_ioctl+0x2db/0x347 drivers/mtd/ubi/cdev.c:1043 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:870 [inline] __se_sys_ioctl fs/ioctl.c:856 [inline] __x64_sys_ioctl+0x193/0x213 fs/ioctl.c:856 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x3e/0x86 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0x0 The buggy address belongs to the object at ffff88802bb36e00 which belongs to the cache kmalloc-256 of size 256 The buggy address is located 0 bytes to the right of 256-byte region [ffff88802bb36e00, ffff88802bb36f00) The buggy address belongs to the physical page: page:00000000ea4d1263 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x2bb36 head:00000000ea4d1263 order:1 compound_mapcount:0 compound_pincount:0 flags: 0xfffffc0010200(slab|head|node=0|zone=1|lastcpupid=0x1fffff) raw: 000fffffc0010200 ffffea000066c300 dead000000000003 ffff888100042b40 raw: 0000000000000000 0000000000100010 00000001ffffffff 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff88802bb36e00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ffff88802bb36e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >ffff88802bb36f00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ^ ffff88802bb36f80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ffff88802bb37000: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ================================================================== Fixes: 801c135ce73d ("UBI: Unsorted Block Images") Reported-by: syzkaller Signed-off-by: George Kennedy Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- drivers/mtd/ubi/build.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index a901f8edfa41..2178eb4115b3 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -663,6 +663,12 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) ubi->ec_hdr_alsize = ALIGN(UBI_EC_HDR_SIZE, ubi->hdrs_min_io_size); ubi->vid_hdr_alsize = ALIGN(UBI_VID_HDR_SIZE, ubi->hdrs_min_io_size); + if (ubi->vid_hdr_offset && ((ubi->vid_hdr_offset + UBI_VID_HDR_SIZE) > + ubi->vid_hdr_alsize)) { + ubi_err(ubi, "VID header offset %d too large.", ubi->vid_hdr_offset); + return -EINVAL; + } + dbg_gen("min_io_size %d", ubi->min_io_size); dbg_gen("max_write_size %d", ubi->max_write_size); dbg_gen("hdrs_min_io_size %d", ubi->hdrs_min_io_size); From 7508453ede98c74396dc860364085168f94ae436 Mon Sep 17 00:00:00 2001 From: Li Hua Date: Mon, 21 Nov 2022 19:18:47 +0800 Subject: [PATCH 025/201] ubifs: Fix build errors as symbol undefined [ Upstream commit aa6d148e6d6270274e3d5a529b71c54cd329d17f ] With CONFIG_UBIFS_FS_AUTHENTICATION not set, the compiler can assume that ubifs_node_check_hash() is never true and drops the call to ubifs_bad_hash(). Is CONFIG_CC_OPTIMIZE_FOR_SIZE enabled this optimization does not happen anymore. So When CONFIG_UBIFS_FS and CONFIG_CC_OPTIMIZE_FOR_SIZE is enabled but CONFIG_UBIFS_FS_AUTHENTICATION is not set, the build errors is as followd: ERROR: modpost: "ubifs_bad_hash" [fs/ubifs/ubifs.ko] undefined! Fix it by add no-op ubifs_bad_hash() for the CONFIG_UBIFS_FS_AUTHENTICATION=n case. Fixes: 16a26b20d2af ("ubifs: authentication: Add hashes to index nodes") Signed-off-by: Li Hua Reviewed-by: Sascha Hauer Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- fs/ubifs/ubifs.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 478bbbb5382f..2f1f31581094 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h @@ -1623,8 +1623,13 @@ static inline int ubifs_check_hmac(const struct ubifs_info *c, return crypto_memneq(expected, got, c->hmac_desc_len); } +#ifdef CONFIG_UBIFS_FS_AUTHENTICATION void ubifs_bad_hash(const struct ubifs_info *c, const void *node, const u8 *hash, int lnum, int offs); +#else +static inline void ubifs_bad_hash(const struct ubifs_info *c, const void *node, + const u8 *hash, int lnum, int offs) {}; +#endif int __ubifs_node_check_hash(const struct ubifs_info *c, const void *buf, const u8 *expected); From 1c5fdf2d4647219d2267ccb08c7f2c7095bf3450 Mon Sep 17 00:00:00 2001 From: Liu Shixin Date: Thu, 20 Oct 2022 12:30:31 +0800 Subject: [PATCH 026/201] ubifs: Fix memory leak in ubifs_sysfs_init() [ Upstream commit 203a55f04f66eea1a1ca7e5a302a7f5c99c62327 ] When insmod ubifs.ko, a kmemleak reported as below: unreferenced object 0xffff88817fb1a780 (size 8): comm "insmod", pid 25265, jiffies 4295239702 (age 100.130s) hex dump (first 8 bytes): 75 62 69 66 73 00 ff ff ubifs... backtrace: [] slab_post_alloc_hook+0x9c/0x3c0 [] __kmalloc_track_caller+0x183/0x410 [] kstrdup+0x3a/0x80 [] kstrdup_const+0x66/0x80 [] kvasprintf_const+0x155/0x190 [] kobject_set_name_vargs+0x5b/0x150 [] kobject_set_name+0xbb/0xf0 [] do_one_initcall+0x14c/0x5a0 [] do_init_module+0x1f0/0x660 [] load_module+0x6d7e/0x7590 [] __do_sys_finit_module+0x19f/0x230 [] __x64_sys_finit_module+0x73/0xb0 [] do_syscall_64+0x35/0x80 [] entry_SYSCALL_64_after_hwframe+0x63/0xcd When kset_register() failed, we should call kset_put to cleanup it. Fixes: 2e3cbf425804 ("ubifs: Export filesystem error counters") Signed-off-by: Liu Shixin Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- fs/ubifs/sysfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ubifs/sysfs.c b/fs/ubifs/sysfs.c index 06ad8fa1fcfb..54270ad36321 100644 --- a/fs/ubifs/sysfs.c +++ b/fs/ubifs/sysfs.c @@ -144,6 +144,8 @@ int __init ubifs_sysfs_init(void) kobject_set_name(&ubifs_kset.kobj, "ubifs"); ubifs_kset.kobj.parent = fs_kobj; ret = kset_register(&ubifs_kset); + if (ret) + kset_put(&ubifs_kset); return ret; } From f9e0748453675636356ffd45b3167a215ba84f53 Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Tue, 11 Oct 2022 11:47:27 +0800 Subject: [PATCH 027/201] ubifs: Rectify space budget for ubifs_symlink() if symlink is encrypted [ Upstream commit c2c36cc6ca23e614f9e4238d0ecf48549ee9002a ] Fix bad space budget when symlink file is encrypted. Bad space budget may let make_reservation() return with -ENOSPC, which could turn ubifs to read-only mode in do_writepage() process. Fetch a reproducer in [Link]. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216490 Fixes: ca7f85be8d6cf9 ("ubifs: Add support for encrypted symlinks") Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- fs/ubifs/dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index 0f29cf201136..aaff3f3f0aa3 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -1151,7 +1151,6 @@ static int ubifs_symlink(struct user_namespace *mnt_userns, struct inode *dir, int err, sz_change, len = strlen(symname); struct fscrypt_str disk_link; struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, - .new_ino_d = ALIGN(len, 8), .dirtied_ino = 1 }; struct fscrypt_name nm; @@ -1167,6 +1166,7 @@ static int ubifs_symlink(struct user_namespace *mnt_userns, struct inode *dir, * Budget request settings: new inode, new direntry and changing parent * directory inode. */ + req.new_ino_d = ALIGN(disk_link.len - 1, 8); err = ubifs_budget_space(c, &req); if (err) return err; From f8bd27b6252a50974e150ac94e394726ecc5cf4e Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Tue, 11 Oct 2022 11:47:28 +0800 Subject: [PATCH 028/201] ubifs: Rectify space budget for ubifs_xrename() [ Upstream commit 1b2ba09060e41adb356b9ae58ef94a7390928004 ] There is no space budget for ubifs_xrename(). It may let make_reservation() return with -ENOSPC, which could turn ubifs to read-only mode in do_writepage() process. Fix it by adding space budget for ubifs_xrename(). Fetch a reproducer in [Link]. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216569 Fixes: 9ec64962afb170 ("ubifs: Implement RENAME_EXCHANGE") Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- fs/ubifs/dir.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index aaff3f3f0aa3..94634b872e38 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -1576,6 +1576,10 @@ static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry, return err; } + err = ubifs_budget_space(c, &req); + if (err) + goto out; + lock_4_inodes(old_dir, new_dir, NULL, NULL); time = current_time(old_dir); @@ -1601,6 +1605,7 @@ static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry, unlock_4_inodes(old_dir, new_dir, NULL, NULL); ubifs_release_budget(c, &req); +out: fscrypt_free_filename(&fst_nm); fscrypt_free_filename(&snd_nm); return err; From b08071c68b586b82c20bb972ed32dd1a8979b12f Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Tue, 11 Oct 2022 11:47:30 +0800 Subject: [PATCH 029/201] ubifs: Fix wrong dirty space budget for dirty inode [ Upstream commit b248eaf049d9cdc5eb76b59399e4d3de233f02ac ] Each dirty inode should reserve 'c->bi.inode_budget' bytes in space budget calculation. Currently, space budget for dirty inode reports more space than what UBIFS actually needs to write. Fixes: 1e51764a3c2ac0 ("UBIFS: add new flash file system") Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- fs/ubifs/budget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ubifs/budget.c b/fs/ubifs/budget.c index e8b9b756f0ac..986e6e4081c7 100644 --- a/fs/ubifs/budget.c +++ b/fs/ubifs/budget.c @@ -400,7 +400,7 @@ static int calc_dd_growth(const struct ubifs_info *c, dd_growth = req->dirtied_page ? c->bi.page_budget : 0; if (req->dirtied_ino) - dd_growth += c->bi.inode_budget << (req->dirtied_ino - 1); + dd_growth += c->bi.inode_budget * req->dirtied_ino; if (req->mod_dent) dd_growth += c->bi.dent_budget; dd_growth += req->dirtied_ino_d; From 31282bc47fcdea044528db9d4f62ecf2fd843868 Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Tue, 11 Oct 2022 11:47:31 +0800 Subject: [PATCH 030/201] ubifs: do_rename: Fix wrong space budget when target inode's nlink > 1 [ Upstream commit 25fce616a61fc2f1821e4a9ce212d0e064707093 ] If target inode is a special file (eg. block/char device) with nlink count greater than 1, the inode with ui->data will be re-written on disk. However, UBIFS losts target inode's data_len while doing space budget. Bad space budget may let make_reservation() return with -ENOSPC, which could turn ubifs to read-only mode in do_writepage() process. Fetch a reproducer in [Link]. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216494 Fixes: 1e51764a3c2ac0 ("UBIFS: add new flash file system") Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- fs/ubifs/dir.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index 94634b872e38..5e6bcce94e64 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -1324,6 +1324,8 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, if (unlink) { ubifs_assert(c, inode_is_locked(new_inode)); + /* Budget for old inode's data when its nlink > 1. */ + req.dirtied_ino_d = ALIGN(ubifs_inode(new_inode)->data_len, 8); err = ubifs_purge_xattrs(new_inode); if (err) return err; From c17e1ae20f6b665fd10b1940c50fed487c5ef429 Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Tue, 11 Oct 2022 11:47:32 +0800 Subject: [PATCH 031/201] ubifs: Reserve one leb for each journal head while doing budget [ Upstream commit e874dcde1cbf82c786c0e7f2899811c02630cc52 ] UBIFS calculates available space by c->main_bytes - c->lst.total_used (which means non-index lebs' free and dirty space is accounted into total available), then index lebs and four lebs (one for gc_lnum, one for deletions, two for journal heads) are deducted. In following situation, ubifs may get -ENOSPC from make_reservation(): LEB 84: DATAHD free 122880 used 1920 dirty 2176 dark 6144 LEB 110:DELETION free 126976 used 0 dirty 0 dark 6144 (empty) LEB 201:gc_lnum free 126976 used 0 dirty 0 dark 6144 LEB 272:GCHD free 77824 used 47672 dirty 1480 dark 6144 LEB 356:BASEHD free 0 used 39776 dirty 87200 dark 6144 OTHERS: index lebs, zero-available non-index lebs UBIFS calculates the available bytes is 6888 (How to calculate it: 126976 * 5[remain main bytes] - 1920[used] - 47672[used] - 39776[used] - 126976 * 1[deletions] - 126976 * 1[gc_lnum] - 126976 * 2[journal heads] - 6144 * 5[dark] = 6888) after doing budget, however UBIFS cannot use BASEHD's dirty space(87200), because UBIFS cannot find next BASEHD to reclaim current BASEHD. (c->bi.min_idx_lebs equals to c->lst.idx_lebs, the empty leb won't be found by ubifs_find_free_space(), and dirty index lebs won't be picked as gced lebs. All non-index lebs has dirty space less then c->dead_wm, non-index lebs won't be picked as gced lebs either. So new free lebs won't be produced.). See more details in Link. To fix it, reserve one leb for each journal head while doing budget. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216562 Fixes: 1e51764a3c2ac0 ("UBIFS: add new flash file system") Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- fs/ubifs/budget.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/ubifs/budget.c b/fs/ubifs/budget.c index 986e6e4081c7..d76eb7b39f56 100644 --- a/fs/ubifs/budget.c +++ b/fs/ubifs/budget.c @@ -209,11 +209,10 @@ long long ubifs_calc_available(const struct ubifs_info *c, int min_idx_lebs) subtract_lebs += 1; /* - * The GC journal head LEB is not really accessible. And since - * different write types go to different heads, we may count only on - * one head's space. + * Since different write types go to different heads, we should + * reserve one leb for each head. */ - subtract_lebs += c->jhead_cnt - 1; + subtract_lebs += c->jhead_cnt; /* We also reserve one LEB for deletions, which bypass budgeting */ subtract_lebs += 1; From b0c951742348d216f094d16ed4f70ae73db881c0 Mon Sep 17 00:00:00 2001 From: Li Zetao Date: Fri, 21 Oct 2022 18:21:56 +0800 Subject: [PATCH 032/201] ubi: Fix use-after-free when volume resizing failed [ Upstream commit 9af31d6ec1a4be4caab2550096c6bd2ba8fba472 ] There is an use-after-free problem reported by KASAN: ================================================================== BUG: KASAN: use-after-free in ubi_eba_copy_table+0x11f/0x1c0 [ubi] Read of size 8 at addr ffff888101eec008 by task ubirsvol/4735 CPU: 2 PID: 4735 Comm: ubirsvol Not tainted 6.1.0-rc1-00003-g84fa3304a7fc-dirty #14 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-1.fc33 04/01/2014 Call Trace: dump_stack_lvl+0x34/0x44 print_report+0x171/0x472 kasan_report+0xad/0x130 ubi_eba_copy_table+0x11f/0x1c0 [ubi] ubi_resize_volume+0x4f9/0xbc0 [ubi] ubi_cdev_ioctl+0x701/0x1850 [ubi] __x64_sys_ioctl+0x11d/0x170 do_syscall_64+0x35/0x80 entry_SYSCALL_64_after_hwframe+0x46/0xb0 When ubi_change_vtbl_record() returns an error in ubi_resize_volume(), "new_eba_tbl" will be freed on error handing path, but it is holded by "vol->eba_tbl" in ubi_eba_replace_table(). It means that the liftcycle of "vol->eba_tbl" and "vol" are different, so when resizing volume in next time, it causing an use-after-free fault. Fix it by not freeing "new_eba_tbl" after it replaced in ubi_eba_replace_table(), while will be freed in next volume resizing. Fixes: 801c135ce73d ("UBI: Unsorted Block Images") Signed-off-by: Li Zetao Reviewed-by: Zhihao Cheng Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- drivers/mtd/ubi/vmt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 8fcc0bdf0635..74637575346e 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -464,7 +464,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) for (i = 0; i < -pebs; i++) { err = ubi_eba_unmap_leb(ubi, vol, reserved_pebs + i); if (err) - goto out_acc; + goto out_free; } spin_lock(&ubi->volumes_lock); ubi->rsvd_pebs += pebs; @@ -512,6 +512,8 @@ out_acc: ubi->avail_pebs += pebs; spin_unlock(&ubi->volumes_lock); } + return err; + out_free: kfree(new_eba_tbl); return err; From 27b760b81951d8d5e5c952a696af8574052b0709 Mon Sep 17 00:00:00 2001 From: Li Zetao Date: Fri, 21 Oct 2022 18:21:57 +0800 Subject: [PATCH 033/201] ubi: Fix unreferenced object reported by kmemleak in ubi_resize_volume() [ Upstream commit 1e591ea072df7211f64542a09482b5f81cb3ad27 ] There is a memory leaks problem reported by kmemleak: unreferenced object 0xffff888102007a00 (size 128): comm "ubirsvol", pid 32090, jiffies 4298464136 (age 2361.231s) hex dump (first 32 bytes): ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ backtrace: [] __kmalloc+0x4d/0x150 [] ubi_eba_create_table+0x76/0x170 [ubi] [] ubi_resize_volume+0x1be/0xbc0 [ubi] [] ubi_cdev_ioctl+0x701/0x1850 [ubi] [] __x64_sys_ioctl+0x11d/0x170 [] do_syscall_64+0x35/0x80 [] entry_SYSCALL_64_after_hwframe+0x46/0xb0 This is due to a mismatch between create and destroy interfaces, and in detail that "new_eba_tbl" created by ubi_eba_create_table() but destroyed by kfree(), while will causing "new_eba_tbl->entries" not freed. Fix it by replacing kfree(new_eba_tbl) with ubi_eba_destroy_table(new_eba_tbl) Fixes: 799dca34ac54 ("UBI: hide EBA internals") Signed-off-by: Li Zetao Reviewed-by: Zhihao Cheng Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- drivers/mtd/ubi/vmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 74637575346e..9fbc64b997ce 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -515,7 +515,7 @@ out_acc: return err; out_free: - kfree(new_eba_tbl); + ubi_eba_destroy_table(new_eba_tbl); return err; } From 26ec45f1c504e15268383019df139d7983f1e67f Mon Sep 17 00:00:00 2001 From: Li Zetao Date: Sat, 22 Oct 2022 19:52:11 +0800 Subject: [PATCH 034/201] ubifs: Fix memory leak in alloc_wbufs() [ Upstream commit 4a1ff3c5d04b9079b4f768d9a71b51c4af578dd2 ] kmemleak reported a sequence of memory leaks, and show them as following: unreferenced object 0xffff8881575f8400 (size 1024): comm "mount", pid 19625, jiffies 4297119604 (age 20.383s) hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [] __kmalloc+0x4d/0x150 [] ubifs_mount+0x307b/0x7170 [ubifs] [] legacy_get_tree+0xed/0x1d0 [] vfs_get_tree+0x7d/0x230 [] path_mount+0xdd4/0x17b0 [] __x64_sys_mount+0x1fa/0x270 [] do_syscall_64+0x35/0x80 [] entry_SYSCALL_64_after_hwframe+0x46/0xb0 unreferenced object 0xffff8881798a6e00 (size 512): comm "mount", pid 19677, jiffies 4297121912 (age 37.816s) hex dump (first 32 bytes): 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk backtrace: [] __kmalloc+0x4d/0x150 [] ubifs_wbuf_init+0x52/0x480 [ubifs] [] ubifs_mount+0x31f5/0x7170 [ubifs] [] legacy_get_tree+0xed/0x1d0 [] vfs_get_tree+0x7d/0x230 [] path_mount+0xdd4/0x17b0 [] __x64_sys_mount+0x1fa/0x270 [] do_syscall_64+0x35/0x80 [] entry_SYSCALL_64_after_hwframe+0x46/0xb0 The problem is that the ubifs_wbuf_init() returns an error in the loop which in the alloc_wbufs(), then the wbuf->buf and wbuf->inodes that were successfully alloced before are not freed. Fix it by adding error hanging path in alloc_wbufs() which frees the memory alloced before when ubifs_wbuf_init() returns an error. Fixes: 1e51764a3c2a ("UBIFS: add new flash file system") Signed-off-by: Li Zetao Reviewed-by: Zhihao Cheng Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- fs/ubifs/super.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index d0c9a09988bc..32cb14759796 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -833,7 +833,7 @@ static int alloc_wbufs(struct ubifs_info *c) INIT_LIST_HEAD(&c->jheads[i].buds_list); err = ubifs_wbuf_init(c, &c->jheads[i].wbuf); if (err) - return err; + goto out_wbuf; c->jheads[i].wbuf.sync_callback = &bud_wbuf_callback; c->jheads[i].wbuf.jhead = i; @@ -841,7 +841,7 @@ static int alloc_wbufs(struct ubifs_info *c) c->jheads[i].log_hash = ubifs_hash_get_desc(c); if (IS_ERR(c->jheads[i].log_hash)) { err = PTR_ERR(c->jheads[i].log_hash); - goto out; + goto out_log_hash; } } @@ -854,9 +854,18 @@ static int alloc_wbufs(struct ubifs_info *c) return 0; -out: - while (i--) +out_log_hash: + kfree(c->jheads[i].wbuf.buf); + kfree(c->jheads[i].wbuf.inodes); + +out_wbuf: + while (i--) { + kfree(c->jheads[i].wbuf.buf); + kfree(c->jheads[i].wbuf.inodes); kfree(c->jheads[i].log_hash); + } + kfree(c->jheads); + c->jheads = NULL; return err; } From 2ea7195b195009ecf0046e55361f393ba96d02db Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Mon, 14 Nov 2022 18:26:24 +0800 Subject: [PATCH 035/201] ubi: Fix possible null-ptr-deref in ubi_free_volume() [ Upstream commit c15859bfd326c10230f09cb48a17f8a35f190342 ] It willl cause null-ptr-deref in the following case: uif_init() ubi_add_volume() cdev_add() -> if it fails, call kill_volumes() device_register() kill_volumes() -> if ubi_add_volume() fails call this function ubi_free_volume() cdev_del() device_unregister() -> trying to delete a not added device, it causes null-ptr-deref So in ubi_free_volume(), it delete devices whether they are added or not, it will causes null-ptr-deref. Handle the error case whlie calling ubi_add_volume() to fix this problem. If add volume fails, set the corresponding vol to null, so it can not be accessed in kill_volumes() and release the resource in ubi_add_volume() error path. Fixes: 801c135ce73d ("UBI: Unsorted Block Images") Suggested-by: Zhihao Cheng Signed-off-by: Yang Yingliang Reviewed-by: Zhihao Cheng Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- drivers/mtd/ubi/build.c | 1 + drivers/mtd/ubi/vmt.c | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 2178eb4115b3..7f65af169751 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -468,6 +468,7 @@ static int uif_init(struct ubi_device *ubi) err = ubi_add_volume(ubi, ubi->volumes[i]); if (err) { ubi_err(ubi, "cannot add volume %d", i); + ubi->volumes[i] = NULL; goto out_volumes; } } diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 9fbc64b997ce..2c867d16f89f 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -582,6 +582,7 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol) if (err) { ubi_err(ubi, "cannot add character device for volume %d, error %d", vol_id, err); + vol_release(&vol->dev); return err; } @@ -592,15 +593,14 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol) vol->dev.groups = volume_dev_groups; dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id); err = device_register(&vol->dev); - if (err) - goto out_cdev; + if (err) { + cdev_del(&vol->cdev); + put_device(&vol->dev); + return err; + } self_check_volumes(ubi); return err; - -out_cdev: - cdev_del(&vol->cdev); - return err; } /** From 0b8beac8a3c5ac1713dd2f9bd2aeb6fc02414ead Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Fri, 18 Nov 2022 17:02:35 +0800 Subject: [PATCH 036/201] ubifs: Re-statistic cleaned znode count if commit failed [ Upstream commit 944e096aa24071d3fe22822f6249d3ae309e39ea ] Dirty znodes will be written on flash in committing process with following states: process A | znode state ------------------------------------------------------ do_commit | DIRTY_ZNODE ubifs_tnc_start_commit | DIRTY_ZNODE get_znodes_to_commit | DIRTY_ZNODE | COW_ZNODE layout_commit | DIRTY_ZNODE | COW_ZNODE fill_gap | 0 write master | 0 or OBSOLETE_ZNODE process B | znode state ------------------------------------------------------ do_commit | DIRTY_ZNODE[1] ubifs_tnc_start_commit | DIRTY_ZNODE get_znodes_to_commit | DIRTY_ZNODE | COW_ZNODE ubifs_tnc_end_commit | DIRTY_ZNODE | COW_ZNODE write_index | 0 write master | 0 or OBSOLETE_ZNODE[2] or | DIRTY_ZNODE[3] [1] znode is dirtied without concurrent committing process [2] znode is copied up (re-dirtied by other process) before cleaned up in committing process [3] znode is re-dirtied after cleaned up in committing process Currently, the clean znode count is updated in free_obsolete_znodes(), which is called only in normal path. If do_commit failed, clean znode count won't be updated, which triggers a failure ubifs assertion[4] in ubifs_tnc_close(): ubifs_assert_failed [ubifs]: UBIFS assert failed: freed == n [4] Commit 380347e9ca7682 ("UBIFS: Add an assertion for clean_zn_cnt"). Fix it by re-statisticing cleaned znode count in tnc_destroy_cnext(). Fetch a reproducer in [Link]. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216704 Fixes: 1e51764a3c2a ("UBIFS: add new flash file system") Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- fs/ubifs/tnc.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c index 488f3da7a6c6..2df56bbc6865 100644 --- a/fs/ubifs/tnc.c +++ b/fs/ubifs/tnc.c @@ -3053,6 +3053,21 @@ static void tnc_destroy_cnext(struct ubifs_info *c) cnext = cnext->cnext; if (ubifs_zn_obsolete(znode)) kfree(znode); + else if (!ubifs_zn_cow(znode)) { + /* + * Don't forget to update clean znode count after + * committing failed, because ubifs will check this + * count while closing tnc. Non-obsolete znode could + * be re-dirtied during committing process, so dirty + * flag is untrustable. The flag 'COW_ZNODE' is set + * for each dirty znode before committing, and it is + * cleared as long as the znode become clean, so we + * can statistic clean znode count according to this + * flag. + */ + atomic_long_inc(&c->clean_zn_cnt); + atomic_long_inc(&ubifs_clean_zn_cnt); + } } while (cnext && cnext != c->cnext); } From 76c488e8a0e2783c6d8753cb7354a420593e8c30 Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Fri, 18 Nov 2022 17:02:36 +0800 Subject: [PATCH 037/201] ubifs: dirty_cow_znode: Fix memleak in error handling path [ Upstream commit 122deabfe1428bffe95e2bf364ff8a5059bdf089 ] Following process will cause a memleak for copied up znode: dirty_cow_znode zn = copy_znode(c, znode); err = insert_old_idx(c, zbr->lnum, zbr->offs); if (unlikely(err)) return ERR_PTR(err); // No one refers to zn. Fix it by adding copied znode back to tnc, then it will be freed by ubifs_destroy_tnc_subtree() while closing tnc. Fetch a reproducer in [Link]. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216705 Fixes: 1e51764a3c2a ("UBIFS: add new flash file system") Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- fs/ubifs/tnc.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c index 2df56bbc6865..2469f72eeaab 100644 --- a/fs/ubifs/tnc.c +++ b/fs/ubifs/tnc.c @@ -267,11 +267,18 @@ static struct ubifs_znode *dirty_cow_znode(struct ubifs_info *c, if (zbr->len) { err = insert_old_idx(c, zbr->lnum, zbr->offs); if (unlikely(err)) - return ERR_PTR(err); + /* + * Obsolete znodes will be freed by tnc_destroy_cnext() + * or free_obsolete_znodes(), copied up znodes should + * be added back to tnc and freed by + * ubifs_destroy_tnc_subtree(). + */ + goto out; err = add_idx_dirt(c, zbr->lnum, zbr->len); } else err = 0; +out: zbr->znode = zn; zbr->lnum = 0; zbr->offs = 0; From 824452d5e90f0fd4896abfaf1f1566094ac27462 Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Wed, 1 Jun 2022 10:59:59 +0800 Subject: [PATCH 038/201] ubifs: ubifs_writepage: Mark page dirty after writing inode failed [ Upstream commit fb8bc4c74ae4526d9489362ab2793a936d072b84 ] There are two states for ubifs writing pages: 1. Dirty, Private 2. Not Dirty, Not Private There is a third possibility which maybe related to [1] that page is private but not dirty caused by following process: PA lock(page) ubifs_write_end attach_page_private // set Private __set_page_dirty_nobuffers // set Dirty unlock(page) write_cache_pages lock(page) clear_page_dirty_for_io(page) // clear Dirty ubifs_writepage write_inode // fail, goto out, following codes are not executed // do_writepage // set_page_writeback // set Writeback // detach_page_private // clear Private // end_page_writeback // clear Writeback out: unlock(page) // Private, Not Dirty PB ksys_fadvise64_64 generic_fadvise invalidate_inode_page // page is neither Dirty nor Writeback invalidate_complete_page // page_has_private is true try_to_release_page ubifs_releasepage ubifs_assert(c, 0) !!! Then we may get following assertion failed: UBIFS error (ubi0:0 pid 1492): ubifs_assert_failed [ubifs]: UBIFS assert failed: 0, in fs/ubifs/file.c:1499 UBIFS warning (ubi0:0 pid 1492): ubifs_ro_mode [ubifs]: switched to read-only mode, error -22 CPU: 2 PID: 1492 Comm: aa Not tainted 5.16.0-rc2-00012-g7bb767dee0ba-dirty Call Trace: dump_stack+0x13/0x1b ubifs_ro_mode+0x54/0x60 [ubifs] ubifs_assert_failed+0x4b/0x80 [ubifs] ubifs_releasepage+0x7e/0x1e0 [ubifs] try_to_release_page+0x57/0xe0 invalidate_inode_page+0xfb/0x130 invalidate_mapping_pagevec+0x12/0x20 generic_fadvise+0x303/0x3c0 vfs_fadvise+0x35/0x40 ksys_fadvise64_64+0x4c/0xb0 Jump [2] to find a reproducer. [1] https://linux-mtd.infradead.narkive.com/NQoBeT1u/patch-rfc-ubifs-fix-assert-failed-in-ubifs-set-page-dirty [2] https://bugzilla.kernel.org/show_bug.cgi?id=215357 Fixes: 1e51764a3c2ac0 ("UBIFS: add new flash file system") Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- fs/ubifs/file.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index f2353dd676ef..1f429260a85f 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -1032,7 +1032,7 @@ static int ubifs_writepage(struct page *page, struct writeback_control *wbc) if (page->index >= synced_i_size >> PAGE_SHIFT) { err = inode->i_sb->s_op->write_inode(inode, NULL); if (err) - goto out_unlock; + goto out_redirty; /* * The inode has been written, but the write-buffer has * not been synchronized, so in case of an unclean @@ -1060,11 +1060,17 @@ static int ubifs_writepage(struct page *page, struct writeback_control *wbc) if (i_size > synced_i_size) { err = inode->i_sb->s_op->write_inode(inode, NULL); if (err) - goto out_unlock; + goto out_redirty; } return do_writepage(page, len); - +out_redirty: + /* + * redirty_page_for_writepage() won't call ubifs_dirty_inode() because + * it passes I_DIRTY_PAGES flag while calling __mark_inode_dirty(), so + * there is no need to do space budget for dirty inode. + */ + redirty_page_for_writepage(wbc, page); out_unlock: unlock_page(page); return err; From 7750be5d3e18500b454714677463b500a0b8b0d8 Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Wed, 1 Jun 2022 11:00:00 +0800 Subject: [PATCH 039/201] ubifs: ubifs_releasepage: Remove ubifs_assert(0) to valid this process [ Upstream commit 66f4742e93523ab2f062d9d9828b3e590bc61536 ] There are two states for ubifs writing pages: 1. Dirty, Private 2. Not Dirty, Not Private The normal process cannot go to ubifs_releasepage() which means there exists pages being private but not dirty. Reproducer[1] shows that it could occur (which maybe related to [2]) with following process: PA PB PC lock(page)[PA] ubifs_write_end attach_page_private // set Private __set_page_dirty_nobuffers // set Dirty unlock(page) write_cache_pages[PA] lock(page) clear_page_dirty_for_io(page) // clear Dirty ubifs_writepage do_truncation[PB] truncate_setsize i_size_write(inode, newsize) // newsize = 0 i_size = i_size_read(inode) // i_size = 0 end_index = i_size >> PAGE_SHIFT if (page->index > end_index) goto out // jump out: unlock(page) // Private, Not Dirty generic_fadvise[PC] lock(page) invalidate_inode_page try_to_release_page ubifs_releasepage ubifs_assert(c, 0) // bad assertion! unlock(page) truncate_pagecache[PB] Then we may get following assertion failed: UBIFS error (ubi0:0 pid 1683): ubifs_assert_failed [ubifs]: UBIFS assert failed: 0, in fs/ubifs/file.c:1513 UBIFS warning (ubi0:0 pid 1683): ubifs_ro_mode [ubifs]: switched to read-only mode, error -22 CPU: 2 PID: 1683 Comm: aa Not tainted 5.16.0-rc5-00184-g0bca5994cacc-dirty #308 Call Trace: dump_stack+0x13/0x1b ubifs_ro_mode+0x54/0x60 [ubifs] ubifs_assert_failed+0x4b/0x80 [ubifs] ubifs_releasepage+0x67/0x1d0 [ubifs] try_to_release_page+0x57/0xe0 invalidate_inode_page+0xfb/0x130 __invalidate_mapping_pages+0xb9/0x280 invalidate_mapping_pagevec+0x12/0x20 generic_fadvise+0x303/0x3c0 ksys_fadvise64_64+0x4c/0xb0 [1] https://bugzilla.kernel.org/show_bug.cgi?id=215373 [2] https://linux-mtd.infradead.narkive.com/NQoBeT1u/patch-rfc-ubifs-fix-assert-failed-in-ubifs-set-page-dirty Fixes: 1e51764a3c2ac0 ("UBIFS: add new flash file system") Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- fs/ubifs/file.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index 1f429260a85f..10c1779af9c5 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -1472,14 +1472,23 @@ static bool ubifs_release_folio(struct folio *folio, gfp_t unused_gfp_flags) struct inode *inode = folio->mapping->host; struct ubifs_info *c = inode->i_sb->s_fs_info; - /* - * An attempt to release a dirty page without budgeting for it - should - * not happen. - */ if (folio_test_writeback(folio)) return false; + + /* + * Page is private but not dirty, weird? There is one condition + * making it happened. ubifs_writepage skipped the page because + * page index beyonds isize (for example. truncated by other + * process named A), then the page is invalidated by fadvise64 + * syscall before being truncated by process A. + */ ubifs_assert(c, folio_test_private(folio)); - ubifs_assert(c, 0); + if (folio_test_checked(folio)) + release_new_page_budget(c); + else + release_existing_page_budget(c); + + atomic_long_dec(&c->dirty_pg_cnt); folio_detach_private(folio); folio_clear_checked(folio); return true; From c670b05127d3a3e110564d43c16dedf85fbb7590 Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Tue, 9 Aug 2022 15:06:19 +0800 Subject: [PATCH 040/201] ubi: fastmap: Fix missed fm_anchor PEB in wear-leveling after disabling fastmap [ Upstream commit 76f9476ece445a07aeb72df9d896cd563fb5b50f ] After disabling fastmap(ubi->fm_disabled = 1), fastmap won't be updated, fm_anchor PEB is missed being scheduled for erasing. Besides, fm_anchor PEB may have smallest erase count, it doesn't participate wear-leveling. The difference of erase count between fm_anchor PEB and other PEBs will be larger and larger later on. In which situation fastmap can be disabled? Initially, we have an UBI image with fastmap. Then the image will be atttached without module parameter 'fm_autoconvert', ubi turns to full scanning mode in one random attaching process(eg. bad fastmap caused by powercut), ubi fastmap is disabled since then. Fix it by not getting fm_anchor if fastmap is disabled in ubi_refill_pools(). Fetch a reproducer in [Link]. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216341 Fixes: 4b68bf9a69d22d ("ubi: Select fastmap anchor PEBs considering ...") Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- drivers/mtd/ubi/fastmap-wl.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/ubi/fastmap-wl.c b/drivers/mtd/ubi/fastmap-wl.c index 0ee452275578..863f571f1adb 100644 --- a/drivers/mtd/ubi/fastmap-wl.c +++ b/drivers/mtd/ubi/fastmap-wl.c @@ -146,13 +146,15 @@ void ubi_refill_pools(struct ubi_device *ubi) if (ubi->fm_anchor) { wl_tree_add(ubi->fm_anchor, &ubi->free); ubi->free_count++; + ubi->fm_anchor = NULL; } - /* - * All available PEBs are in ubi->free, now is the time to get - * the best anchor PEBs. - */ - ubi->fm_anchor = ubi_wl_get_fm_peb(ubi, 1); + if (!ubi->fm_disabled) + /* + * All available PEBs are in ubi->free, now is the time to get + * the best anchor PEBs. + */ + ubi->fm_anchor = ubi_wl_get_fm_peb(ubi, 1); for (;;) { enough = 0; From 84253f3c2dad6be10d30c92626c763d9a9f512ad Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Sat, 30 Jul 2022 19:28:37 +0800 Subject: [PATCH 041/201] ubi: Fix UAF wear-leveling entry in eraseblk_count_seq_show() [ Upstream commit a240bc5c43130c6aa50831d7caaa02a1d84e1bce ] Wear-leveling entry could be freed in error path, which may be accessed again in eraseblk_count_seq_show(), for example: __erase_worker eraseblk_count_seq_show wl = ubi->lookuptbl[*block_number] if (wl) wl_entry_destroy ubi->lookuptbl[e->pnum] = NULL kmem_cache_free(ubi_wl_entry_slab, e) erase_count = wl->ec // UAF! Wear-leveling entry updating/accessing in ubi->lookuptbl should be protected by ubi->wl_lock, fix it by adding ubi->wl_lock to serialize wl entry accessing between wl_entry_destroy() and eraseblk_count_seq_show(). Fetch a reproducer in [Link]. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216305 Fixes: 7bccd12d27b7e3 ("ubi: Add debugfs file for tracking PEB state") Fixes: 801c135ce73d5d ("UBI: Unsorted Block Images") Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- drivers/mtd/ubi/wl.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 68eb0f21b3fe..f45df3b77373 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -890,8 +890,11 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, err = do_sync_erase(ubi, e1, vol_id, lnum, 0); if (err) { - if (e2) + if (e2) { + spin_lock(&ubi->wl_lock); wl_entry_destroy(ubi, e2); + spin_unlock(&ubi->wl_lock); + } goto out_ro; } @@ -1130,14 +1133,18 @@ static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk) /* Re-schedule the LEB for erasure */ err1 = schedule_erase(ubi, e, vol_id, lnum, 0, false); if (err1) { + spin_lock(&ubi->wl_lock); wl_entry_destroy(ubi, e); + spin_unlock(&ubi->wl_lock); err = err1; goto out_ro; } return err; } + spin_lock(&ubi->wl_lock); wl_entry_destroy(ubi, e); + spin_unlock(&ubi->wl_lock); if (err != -EIO) /* * If this is not %-EIO, we have no idea what to do. Scheduling From cc4bc532acda66189bddc03b3fe1ad689d9a48a2 Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Mon, 13 Jun 2022 14:59:04 +0800 Subject: [PATCH 042/201] ubi: ubi_wl_put_peb: Fix infinite loop when wear-leveling work failed [ Upstream commit 4d57a7333e26040f2b583983e1970d9d460e56b0 ] Following process will trigger an infinite loop in ubi_wl_put_peb(): ubifs_bgt ubi_bgt ubifs_leb_unmap ubi_leb_unmap ubi_eba_unmap_leb ubi_wl_put_peb wear_leveling_worker e1 = rb_entry(rb_first(&ubi->used) e2 = get_peb_for_wl(ubi) ubi_io_read_vid_hdr // return err (flash fault) out_error: ubi->move_from = ubi->move_to = NULL wl_entry_destroy(ubi, e1) ubi->lookuptbl[e->pnum] = NULL retry: e = ubi->lookuptbl[pnum]; // return NULL if (e == ubi->move_from) { // NULL == NULL gets true goto retry; // infinite loop !!! $ top PID USER PR NI VIRT RES SHR S %CPU %MEM COMMAND 7676 root 20 0 0 0 0 R 100.0 0.0 ubifs_bgt0_0 Fix it by: 1) Letting ubi_wl_put_peb() returns directly if wearl leveling entry has been removed from 'ubi->lookuptbl'. 2) Using 'ubi->wl_lock' protecting wl entry deletion to preventing an use-after-free problem for wl entry in ubi_wl_put_peb(). Fetch a reproducer in [Link]. Fixes: 43f9b25a9cdd7b1 ("UBI: bugfix: protect from volume removal") Fixes: ee59ba8b064f692 ("UBI: Fix stale pointers in ubi->lookuptbl") Link: https://bugzilla.kernel.org/show_bug.cgi?id=216111 Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- drivers/mtd/ubi/wl.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index f45df3b77373..9e14319225c9 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -976,11 +976,11 @@ out_error: spin_lock(&ubi->wl_lock); ubi->move_from = ubi->move_to = NULL; ubi->move_to_put = ubi->wl_scheduled = 0; + wl_entry_destroy(ubi, e1); + wl_entry_destroy(ubi, e2); spin_unlock(&ubi->wl_lock); ubi_free_vid_buf(vidb); - wl_entry_destroy(ubi, e1); - wl_entry_destroy(ubi, e2); out_ro: ubi_ro_mode(ubi); @@ -1260,6 +1260,18 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int vol_id, int lnum, retry: spin_lock(&ubi->wl_lock); e = ubi->lookuptbl[pnum]; + if (!e) { + /* + * This wl entry has been removed for some errors by other + * process (eg. wear leveling worker), corresponding process + * (except __erase_worker, which cannot concurrent with + * ubi_wl_put_peb) will set ubi ro_mode at the same time, + * just ignore this wl entry. + */ + spin_unlock(&ubi->wl_lock); + up_read(&ubi->fm_protect); + return 0; + } if (e == ubi->move_from) { /* * User is putting the physical eraseblock which was selected to From 22ddbbff116ee7dce5431feb1c0f36a507d2d68d Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sat, 21 Jan 2023 00:16:55 +0800 Subject: [PATCH 043/201] f2fs: fix to avoid potential memory corruption in __update_iostat_latency() [ Upstream commit 0dbbf0fb38d5ec5d4138d1aeaeb43d9217b9a592 ] Add iotype sanity check to avoid potential memory corruption. This is to fix the compile error below: fs/f2fs/iostat.c:231 __update_iostat_latency() error: buffer overflow 'io_lat->peak_lat[type]' 3 <= 3 vim +228 fs/f2fs/iostat.c 211 static inline void __update_iostat_latency(struct bio_iostat_ctx *iostat_ctx, 212 enum iostat_lat_type type) 213 { 214 unsigned long ts_diff; 215 unsigned int page_type = iostat_ctx->type; 216 struct f2fs_sb_info *sbi = iostat_ctx->sbi; 217 struct iostat_lat_info *io_lat = sbi->iostat_io_lat; 218 unsigned long flags; 219 220 if (!sbi->iostat_enable) 221 return; 222 223 ts_diff = jiffies - iostat_ctx->submit_ts; 224 if (page_type >= META_FLUSH) ^^^^^^^^^^ 225 page_type = META; 226 227 spin_lock_irqsave(&sbi->iostat_lat_lock, flags); @228 io_lat->sum_lat[type][page_type] += ts_diff; ^^^^^^^^^ Mixup between META_FLUSH and NR_PAGE_TYPE leads to memory corruption. Fixes: a4b6817625e7 ("f2fs: introduce periodic iostat io latency traces") Reported-by: kernel test robot Reported-by: Dan Carpenter Suggested-by: Chao Yu Suggested-by: Jaegeuk Kim Signed-off-by: Yangtao Li Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin --- fs/f2fs/iostat.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/iostat.c b/fs/f2fs/iostat.c index 3166a8939ed4..02393c95c9f8 100644 --- a/fs/f2fs/iostat.c +++ b/fs/f2fs/iostat.c @@ -227,8 +227,12 @@ static inline void __update_iostat_latency(struct bio_iostat_ctx *iostat_ctx, return; ts_diff = jiffies - iostat_ctx->submit_ts; - if (iotype >= META_FLUSH) + if (iotype == META_FLUSH) { iotype = META; + } else if (iotype >= NR_PAGE_TYPE) { + f2fs_warn(sbi, "%s: %d over NR_PAGE_TYPE", __func__, iotype); + return; + } if (rw == 0) { idx = READ_IO; From 0bf3672946a39637d7443397a7f66382436a3935 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 18 Jan 2023 19:23:29 -0800 Subject: [PATCH 044/201] soc: qcom: stats: Populate all subsystem debugfs files [ Upstream commit acdbf5f9b2c492505145f6e50c65418521a547c4 ] This driver relies on SMEM to populate items for each subsystem before the device probes. The items in SMEM that are being looked for are populated by the subsystems lazily, and therefore may not exist until the device has booted. For example, if I build this driver into the kernel on Trogdor Lazor and boot up, I don't see a 'modem' debugfs file populated, because the modem boots and populates the SMEM item after this driver probes. Always populate the files for the subsystems if they're in SMEM, and make the qcom_subsystem_sleep_stats_show() function return 0 if the SMEM items still isn't there. This way we can run a simple command like grep ^ /sys/kernel/debug/qcom_stats/* and collect the subsystem sleep stats without interspersed errors or missing details entirely because this driver probed first. Fixes: 1d7724690344 ("soc: qcom: Add Sleep stats driver") Cc: Matthias Kaehlcke Signed-off-by: Stephen Boyd Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20230119032329.2909383-1-swboyd@chromium.org Signed-off-by: Sasha Levin --- drivers/soc/qcom/qcom_stats.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/soc/qcom/qcom_stats.c b/drivers/soc/qcom/qcom_stats.c index 121ea409fafc..b252bedf0cf1 100644 --- a/drivers/soc/qcom/qcom_stats.c +++ b/drivers/soc/qcom/qcom_stats.c @@ -92,7 +92,7 @@ static int qcom_subsystem_sleep_stats_show(struct seq_file *s, void *unused) /* Items are allocated lazily, so lookup pointer each time */ stat = qcom_smem_get(subsystem->pid, subsystem->smem_item, NULL); if (IS_ERR(stat)) - return -EIO; + return 0; qcom_print_stats(s, stat); @@ -170,20 +170,14 @@ static void qcom_create_soc_sleep_stat_files(struct dentry *root, void __iomem * static void qcom_create_subsystem_stat_files(struct dentry *root, const struct stats_config *config) { - const struct sleep_stats *stat; int i; if (!config->subsystem_stats_in_smem) return; - for (i = 0; i < ARRAY_SIZE(subsystems); i++) { - stat = qcom_smem_get(subsystems[i].pid, subsystems[i].smem_item, NULL); - if (IS_ERR(stat)) - continue; - + for (i = 0; i < ARRAY_SIZE(subsystems); i++) debugfs_create_file(subsystems[i].name, 0400, root, (void *)&subsystems[i], &qcom_subsystem_sleep_stats_fops); - } } static int qcom_stats_probe(struct platform_device *pdev) From aa936286e71aff9185b21d56e54b432d46394c81 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 16 Dec 2022 21:02:12 -0800 Subject: [PATCH 045/201] ext4: use ext4_fc_tl_mem in fast-commit replay path [ Upstream commit 11768cfd98136dd8399480c60b7a5d3d3c7b109b ] To avoid 'sparse' warnings about missing endianness conversions, don't store native endianness values into struct ext4_fc_tl. Instead, use a separate struct type, ext4_fc_tl_mem. Fixes: dcc5827484d6 ("ext4: factor out ext4_fc_get_tl()") Cc: Ye Bin Signed-off-by: Eric Biggers Reviewed-by: Jan Kara Link: https://lore.kernel.org/r/20221217050212.150665-1-ebiggers@kernel.org Signed-off-by: Theodore Ts'o Signed-off-by: Sasha Levin --- fs/ext4/fast_commit.c | 44 +++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/fs/ext4/fast_commit.c b/fs/ext4/fast_commit.c index 7ed71c652f67..1110bfa0a5b7 100644 --- a/fs/ext4/fast_commit.c +++ b/fs/ext4/fast_commit.c @@ -1354,8 +1354,14 @@ struct dentry_info_args { char *dname; }; +/* Same as struct ext4_fc_tl, but uses native endianness fields */ +struct ext4_fc_tl_mem { + u16 fc_tag; + u16 fc_len; +}; + static inline void tl_to_darg(struct dentry_info_args *darg, - struct ext4_fc_tl *tl, u8 *val) + struct ext4_fc_tl_mem *tl, u8 *val) { struct ext4_fc_dentry_info fcd; @@ -1367,16 +1373,18 @@ static inline void tl_to_darg(struct dentry_info_args *darg, darg->dname_len = tl->fc_len - sizeof(struct ext4_fc_dentry_info); } -static inline void ext4_fc_get_tl(struct ext4_fc_tl *tl, u8 *val) +static inline void ext4_fc_get_tl(struct ext4_fc_tl_mem *tl, u8 *val) { - memcpy(tl, val, EXT4_FC_TAG_BASE_LEN); - tl->fc_len = le16_to_cpu(tl->fc_len); - tl->fc_tag = le16_to_cpu(tl->fc_tag); + struct ext4_fc_tl tl_disk; + + memcpy(&tl_disk, val, EXT4_FC_TAG_BASE_LEN); + tl->fc_len = le16_to_cpu(tl_disk.fc_len); + tl->fc_tag = le16_to_cpu(tl_disk.fc_tag); } /* Unlink replay function */ -static int ext4_fc_replay_unlink(struct super_block *sb, struct ext4_fc_tl *tl, - u8 *val) +static int ext4_fc_replay_unlink(struct super_block *sb, + struct ext4_fc_tl_mem *tl, u8 *val) { struct inode *inode, *old_parent; struct qstr entry; @@ -1473,8 +1481,8 @@ out: } /* Link replay function */ -static int ext4_fc_replay_link(struct super_block *sb, struct ext4_fc_tl *tl, - u8 *val) +static int ext4_fc_replay_link(struct super_block *sb, + struct ext4_fc_tl_mem *tl, u8 *val) { struct inode *inode; struct dentry_info_args darg; @@ -1528,8 +1536,8 @@ static int ext4_fc_record_modified_inode(struct super_block *sb, int ino) /* * Inode replay function */ -static int ext4_fc_replay_inode(struct super_block *sb, struct ext4_fc_tl *tl, - u8 *val) +static int ext4_fc_replay_inode(struct super_block *sb, + struct ext4_fc_tl_mem *tl, u8 *val) { struct ext4_fc_inode fc_inode; struct ext4_inode *raw_inode; @@ -1631,8 +1639,8 @@ out: * inode for which we are trying to create a dentry here, should already have * been replayed before we start here. */ -static int ext4_fc_replay_create(struct super_block *sb, struct ext4_fc_tl *tl, - u8 *val) +static int ext4_fc_replay_create(struct super_block *sb, + struct ext4_fc_tl_mem *tl, u8 *val) { int ret = 0; struct inode *inode = NULL; @@ -1730,7 +1738,7 @@ int ext4_fc_record_regions(struct super_block *sb, int ino, /* Replay add range tag */ static int ext4_fc_replay_add_range(struct super_block *sb, - struct ext4_fc_tl *tl, u8 *val) + struct ext4_fc_tl_mem *tl, u8 *val) { struct ext4_fc_add_range fc_add_ex; struct ext4_extent newex, *ex; @@ -1850,8 +1858,8 @@ out: /* Replay DEL_RANGE tag */ static int -ext4_fc_replay_del_range(struct super_block *sb, struct ext4_fc_tl *tl, - u8 *val) +ext4_fc_replay_del_range(struct super_block *sb, + struct ext4_fc_tl_mem *tl, u8 *val) { struct inode *inode; struct ext4_fc_del_range lrange; @@ -2047,7 +2055,7 @@ static int ext4_fc_replay_scan(journal_t *journal, struct ext4_fc_replay_state *state; int ret = JBD2_FC_REPLAY_CONTINUE; struct ext4_fc_add_range ext; - struct ext4_fc_tl tl; + struct ext4_fc_tl_mem tl; struct ext4_fc_tail tail; __u8 *start, *end, *cur, *val; struct ext4_fc_head head; @@ -2166,7 +2174,7 @@ static int ext4_fc_replay(journal_t *journal, struct buffer_head *bh, { struct super_block *sb = journal->j_private; struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_fc_tl tl; + struct ext4_fc_tl_mem tl; __u8 *start, *end, *cur, *val; int ret = JBD2_FC_REPLAY_CONTINUE; struct ext4_fc_replay_state *state = &sbi->s_fc_replay_state; From 13a6366bbfa2c07694daf14c47fa50c978c25119 Mon Sep 17 00:00:00 2001 From: Wang Jianjian Date: Mon, 19 Dec 2022 09:51:28 +0800 Subject: [PATCH 046/201] ext4: don't show commit interval if it is zero [ Upstream commit 934b0de1e9fdea93c4c7f2e18915c54fae67bdc6 ] If commit interval is 0, it means using default value. Fixes: 6e47a3cc68fc ("ext4: get rid of super block and sbi from handle_mount_ops()") Signed-off-by: Wang Jianjian Link: https://lore.kernel.org/r/20221219015128.876717-1-wangjianjian3@huawei.com Signed-off-by: Theodore Ts'o Signed-off-by: Sasha Levin --- fs/ext4/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index aa4f65663fad..22ddd89c868a 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -2146,7 +2146,7 @@ static int ext4_parse_param(struct fs_context *fc, struct fs_parameter *param) return 0; case Opt_commit: if (result.uint_32 == 0) - ctx->s_commit_interval = JBD2_DEFAULT_MAX_COMMIT_AGE; + result.uint_32 = JBD2_DEFAULT_MAX_COMMIT_AGE; else if (result.uint_32 > INT_MAX / HZ) { ext4_msg(NULL, KERN_ERR, "Invalid commit interval %d, " From 44b713a242510cfb3aeed4fc96e8d680065152a9 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 8 Feb 2023 11:34:27 +0100 Subject: [PATCH 047/201] netfilter: nf_tables: allow to fetch set elements when table has an owner [ Upstream commit 92f3e96d642f5e05b9dc710c06fedc669f1b4f00 ] NFT_MSG_GETSETELEM returns -EPERM when fetching set elements that belong to table that has an owner. This results in empty set/map listing from userspace. Fixes: 6001a930ce03 ("netfilter: nftables: introduce table ownership") Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- net/netfilter/nf_tables_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index dca5352bdf3d..1a9d759d0a02 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -5439,7 +5439,7 @@ static int nf_tables_getsetelem(struct sk_buff *skb, int rem, err = 0; table = nft_table_lookup(net, nla[NFTA_SET_ELEM_LIST_TABLE], family, - genmask, NETLINK_CB(skb).portid); + genmask, 0); if (IS_ERR(table)) { NL_SET_BAD_ATTR(extack, nla[NFTA_SET_ELEM_LIST_TABLE]); return PTR_ERR(table); From 28ebc1164a45db27261ad8440dcbe9238beaf32a Mon Sep 17 00:00:00 2001 From: Ammar Faizi Date: Sat, 24 Dec 2022 00:23:38 +0700 Subject: [PATCH 048/201] x86: um: vdso: Add '%rcx' and '%r11' to the syscall clobber list [ Upstream commit 5541992e512de8c9133110809f767bd1b54ee10d ] The 'syscall' instruction clobbers '%rcx' and '%r11', but they are not listed in the inline Assembly that performs the syscall instruction. No real bug is found. It wasn't buggy by luck because '%rcx' and '%r11' are caller-saved registers, and not used in the functions, and the functions are never inlined. Add them to the clobber list for code correctness. Fixes: f1c2bb8b9964ed31de988910f8b1cfb586d30091 ("um: implement a x86_64 vDSO") Signed-off-by: Ammar Faizi Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- arch/x86/um/vdso/um_vdso.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/x86/um/vdso/um_vdso.c b/arch/x86/um/vdso/um_vdso.c index 2112b8d14668..ff0f3b4b6c45 100644 --- a/arch/x86/um/vdso/um_vdso.c +++ b/arch/x86/um/vdso/um_vdso.c @@ -17,8 +17,10 @@ int __vdso_clock_gettime(clockid_t clock, struct __kernel_old_timespec *ts) { long ret; - asm("syscall" : "=a" (ret) : - "0" (__NR_clock_gettime), "D" (clock), "S" (ts) : "memory"); + asm("syscall" + : "=a" (ret) + : "0" (__NR_clock_gettime), "D" (clock), "S" (ts) + : "rcx", "r11", "memory"); return ret; } @@ -29,8 +31,10 @@ int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) { long ret; - asm("syscall" : "=a" (ret) : - "0" (__NR_gettimeofday), "D" (tv), "S" (tz) : "memory"); + asm("syscall" + : "=a" (ret) + : "0" (__NR_gettimeofday), "D" (tv), "S" (tz) + : "rcx", "r11", "memory"); return ret; } From 4e774bf6ea50030dee58598c0fc2697a43409965 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 9 Feb 2023 10:00:02 +0100 Subject: [PATCH 049/201] um: virtio_uml: free command if adding to virtqueue failed [ Upstream commit 8a6ca543646f2940832665dbf4e04105262505e2 ] If adding the command fails (i.e. the virtqueue is broken) then free it again if the function allocated a new buffer for it. Fixes: 68f5d3f3b654 ("um: add PCI over virtio emulation driver") Signed-off-by: Benjamin Berg Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- arch/um/drivers/virt-pci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/um/drivers/virt-pci.c b/arch/um/drivers/virt-pci.c index 3ac220dafec4..3b637ad75ec8 100644 --- a/arch/um/drivers/virt-pci.c +++ b/arch/um/drivers/virt-pci.c @@ -132,8 +132,11 @@ static int um_pci_send_cmd(struct um_pci_device *dev, out ? 1 : 0, posted ? cmd : HANDLE_NO_FREE(cmd), GFP_ATOMIC); - if (ret) + if (ret) { + if (posted) + kfree(cmd); goto out; + } if (posted) { virtqueue_kick(dev->cmd_vq); From 1954d3cd49d357146b99e38eee874f281fed4bfb Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 9 Feb 2023 10:00:03 +0100 Subject: [PATCH 050/201] um: virtio_uml: mark device as unregistered when breaking it [ Upstream commit 8e9cd85139a2149d5a7c121b05e0cdb8287311f9 ] Mark the device as not registered anymore when scheduling the work to remove it. Otherwise we could end up scheduling the work multiple times in a row, including scheduling it while it is already running. Fixes: af9fb41ed315 ("um: virtio_uml: Fix broken device handling in time-travel") Signed-off-by: Benjamin Berg Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- arch/um/drivers/virtio_uml.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c index 588930a0ced1..dcfd0ca534ee 100644 --- a/arch/um/drivers/virtio_uml.c +++ b/arch/um/drivers/virtio_uml.c @@ -168,6 +168,8 @@ static void vhost_user_check_reset(struct virtio_uml_device *vu_dev, if (!vu_dev->registered) return; + vu_dev->registered = 0; + virtio_break_device(&vu_dev->vdev); schedule_work(&pdata->conn_broken_wk); } From e38d2adf110c5ea079b41ced00984425757a8b80 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 9 Feb 2023 10:00:04 +0100 Subject: [PATCH 051/201] um: virtio_uml: move device breaking into workqueue [ Upstream commit abdeb4fa5e1b5b4918034f02236fd886f40c20c1 ] We should not be calling virtio_break_device from an IRQ context. Move breaking the device into the workqueue so that it is done from a reasonable context. Fixes: af9fb41ed315 ("um: virtio_uml: Fix broken device handling in time-travel") Signed-off-by: Benjamin Berg Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- arch/um/drivers/virtio_uml.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c index dcfd0ca534ee..ddd080f6dd82 100644 --- a/arch/um/drivers/virtio_uml.c +++ b/arch/um/drivers/virtio_uml.c @@ -170,7 +170,6 @@ static void vhost_user_check_reset(struct virtio_uml_device *vu_dev, vu_dev->registered = 0; - virtio_break_device(&vu_dev->vdev); schedule_work(&pdata->conn_broken_wk); } @@ -1138,6 +1137,15 @@ void virtio_uml_set_no_vq_suspend(struct virtio_device *vdev, static void vu_of_conn_broken(struct work_struct *wk) { + struct virtio_uml_platform_data *pdata; + struct virtio_uml_device *vu_dev; + + pdata = container_of(wk, struct virtio_uml_platform_data, conn_broken_wk); + + vu_dev = platform_get_drvdata(pdata->pdev); + + virtio_break_device(&vu_dev->vdev); + /* * We can't remove the device from the devicetree so the only thing we * can do is warn. @@ -1268,8 +1276,14 @@ static int vu_unregister_cmdline_device(struct device *dev, void *data) static void vu_conn_broken(struct work_struct *wk) { struct virtio_uml_platform_data *pdata; + struct virtio_uml_device *vu_dev; pdata = container_of(wk, struct virtio_uml_platform_data, conn_broken_wk); + + vu_dev = platform_get_drvdata(pdata->pdev); + + virtio_break_device(&vu_dev->vdev); + vu_unregister_cmdline_device(&pdata->pdev->dev, NULL); } From a02a91057652d98a1445808070ae5e968417741b Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 9 Feb 2023 10:00:05 +0100 Subject: [PATCH 052/201] um: virt-pci: properly remove PCI device from bus [ Upstream commit 339b84dcd7113dd076419ea2a47128cc53450305 ] Triggering a bus rescan will not cause the PCI device to be removed. It is required to explicitly stop and remove the device from the bus. Fixes: 68f5d3f3b654 ("um: add PCI over virtio emulation driver") Signed-off-by: Benjamin Berg Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- arch/um/drivers/virt-pci.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/arch/um/drivers/virt-pci.c b/arch/um/drivers/virt-pci.c index 3b637ad75ec8..5472b1a0a039 100644 --- a/arch/um/drivers/virt-pci.c +++ b/arch/um/drivers/virt-pci.c @@ -626,22 +626,33 @@ static void um_pci_virtio_remove(struct virtio_device *vdev) struct um_pci_device *dev = vdev->priv; int i; - /* Stop all virtqueues */ - virtio_reset_device(vdev); - vdev->config->del_vqs(vdev); - device_set_wakeup_enable(&vdev->dev, false); mutex_lock(&um_pci_mtx); for (i = 0; i < MAX_DEVICES; i++) { if (um_pci_devices[i].dev != dev) continue; + um_pci_devices[i].dev = NULL; irq_free_desc(dev->irq); + + break; } mutex_unlock(&um_pci_mtx); - um_pci_rescan(); + if (i < MAX_DEVICES) { + struct pci_dev *pci_dev; + + pci_dev = pci_get_slot(bridge->bus, i); + if (pci_dev) + pci_stop_and_remove_bus_device_locked(pci_dev); + } + + /* Stop all virtqueues */ + virtio_reset_device(vdev); + dev->cmd_vq = NULL; + dev->irq_vq = NULL; + vdev->config->del_vqs(vdev); kfree(dev); } From 102b82708c1523b36d421cb8687746906069bc17 Mon Sep 17 00:00:00 2001 From: Daeho Jeong Date: Thu, 9 Feb 2023 10:18:19 -0800 Subject: [PATCH 053/201] f2fs: synchronize atomic write aborts [ Upstream commit a46bebd502fe1a3bd1d22f64cedd93e7e7702693 ] To fix a race condition between atomic write aborts, I use the inode lock and make COW inode to be re-usable thoroughout the whole atomic file inode lifetime. Reported-by: syzbot+823000d23b3400619f7c@syzkaller.appspotmail.com Fixes: 3db1de0e582c ("f2fs: change the current atomic write way") Signed-off-by: Daeho Jeong Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin --- fs/f2fs/file.c | 44 +++++++++++++++++++++++++++++--------------- fs/f2fs/inode.c | 11 +++++++++-- fs/f2fs/segment.c | 3 --- fs/f2fs/super.c | 2 -- 4 files changed, 38 insertions(+), 22 deletions(-) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 8a576c004b72..773b3ddc2cd7 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1865,7 +1865,10 @@ static int f2fs_release_file(struct inode *inode, struct file *filp) atomic_read(&inode->i_writecount) != 1) return 0; + inode_lock(inode); f2fs_abort_atomic_write(inode, true); + inode_unlock(inode); + return 0; } @@ -1880,8 +1883,12 @@ static int f2fs_file_flush(struct file *file, fl_owner_t id) * before dropping file lock, it needs to do in ->flush. */ if (F2FS_I(inode)->atomic_write_task == current && - (current->flags & PF_EXITING)) + (current->flags & PF_EXITING)) { + inode_lock(inode); f2fs_abort_atomic_write(inode, true); + inode_unlock(inode); + } + return 0; } @@ -2087,19 +2094,28 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) goto out; } - /* Create a COW inode for atomic write */ - pinode = f2fs_iget(inode->i_sb, fi->i_pino); - if (IS_ERR(pinode)) { - f2fs_up_write(&fi->i_gc_rwsem[WRITE]); - ret = PTR_ERR(pinode); - goto out; - } + /* Check if the inode already has a COW inode */ + if (fi->cow_inode == NULL) { + /* Create a COW inode for atomic write */ + pinode = f2fs_iget(inode->i_sb, fi->i_pino); + if (IS_ERR(pinode)) { + f2fs_up_write(&fi->i_gc_rwsem[WRITE]); + ret = PTR_ERR(pinode); + goto out; + } - ret = f2fs_get_tmpfile(mnt_userns, pinode, &fi->cow_inode); - iput(pinode); - if (ret) { - f2fs_up_write(&fi->i_gc_rwsem[WRITE]); - goto out; + ret = f2fs_get_tmpfile(mnt_userns, pinode, &fi->cow_inode); + iput(pinode); + if (ret) { + f2fs_up_write(&fi->i_gc_rwsem[WRITE]); + goto out; + } + + set_inode_flag(fi->cow_inode, FI_COW_FILE); + clear_inode_flag(fi->cow_inode, FI_INLINE_DATA); + } else { + /* Reuse the already created COW inode */ + f2fs_do_truncate_blocks(fi->cow_inode, 0, true); } f2fs_write_inode(inode, NULL); @@ -2111,8 +2127,6 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) stat_inc_atomic_inode(inode); set_inode_flag(inode, FI_ATOMIC_FILE); - set_inode_flag(fi->cow_inode, FI_COW_FILE); - clear_inode_flag(fi->cow_inode, FI_INLINE_DATA); f2fs_up_write(&fi->i_gc_rwsem[WRITE]); f2fs_update_time(sbi, REQ_TIME); diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index e8413b080e0a..229ddc2f7b07 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -764,11 +764,18 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) void f2fs_evict_inode(struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - nid_t xnid = F2FS_I(inode)->i_xattr_nid; + struct f2fs_inode_info *fi = F2FS_I(inode); + nid_t xnid = fi->i_xattr_nid; int err = 0; f2fs_abort_atomic_write(inode, true); + if (fi->cow_inode) { + clear_inode_flag(fi->cow_inode, FI_COW_FILE); + iput(fi->cow_inode); + fi->cow_inode = NULL; + } + trace_f2fs_evict_inode(inode); truncate_inode_pages_final(&inode->i_data); @@ -855,7 +862,7 @@ no_delete: stat_dec_inline_inode(inode); stat_dec_compr_inode(inode); stat_sub_compr_blocks(inode, - atomic_read(&F2FS_I(inode)->i_compr_blocks)); + atomic_read(&fi->i_compr_blocks)); if (likely(!f2fs_cp_error(sbi) && !is_sbi_flag_set(sbi, SBI_CP_DISABLED))) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 63c689409979..8d1e8c537daf 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -192,9 +192,6 @@ void f2fs_abort_atomic_write(struct inode *inode, bool clean) if (!f2fs_is_atomic_file(inode)) return; - clear_inode_flag(fi->cow_inode, FI_COW_FILE); - iput(fi->cow_inode); - fi->cow_inode = NULL; release_atomic_write_cnt(inode); clear_inode_flag(inode, FI_ATOMIC_COMMITTED); clear_inode_flag(inode, FI_ATOMIC_FILE); diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index eaabb85cb4dd..14c87399efea 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1416,8 +1416,6 @@ static int f2fs_drop_inode(struct inode *inode) atomic_inc(&inode->i_count); spin_unlock(&inode->i_lock); - f2fs_abort_atomic_write(inode, true); - /* should remain fi->extent_tree for writepage */ f2fs_destroy_extent_node(inode); From edaed0cd769589765fc4d84ee6c9c59bea025e55 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Thu, 17 Nov 2022 11:49:06 +0000 Subject: [PATCH 054/201] watchdog: rzg2l_wdt: Issue a reset before we put the PM clocks [ Upstream commit 6ba6f0f5910d5916539268c0ad55657bb8940616 ] On RZ/Five SoC it was observed that setting timeout (to say 1 sec) wouldn't reset the system. The procedure described in the HW manual (Procedure for Activating Modules) for activating the target module states we need to start supply of the clock module before applying the reset signal. This patch makes sure we follow the same procedure to clear the registers of the WDT module, fixing the issues seen on RZ/Five SoC. While at it re-used rzg2l_wdt_stop() in rzg2l_wdt_set_timeout() as it has the same function calls. Fixes: 4055ee81009e ("watchdog: rzg2l_wdt: Add set_timeout callback") Signed-off-by: Lad Prabhakar Reviewed-by: Guenter Roeck Reviewed-by: Geert Uytterhoeven Reviewed-by: Biju Das Link: https://lore.kernel.org/r/20221117114907.138583-2-fabrizio.castro.jz@renesas.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Sasha Levin --- drivers/watchdog/rzg2l_wdt.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/watchdog/rzg2l_wdt.c b/drivers/watchdog/rzg2l_wdt.c index 974a4194a8fd..ceca42db0837 100644 --- a/drivers/watchdog/rzg2l_wdt.c +++ b/drivers/watchdog/rzg2l_wdt.c @@ -115,25 +115,23 @@ static int rzg2l_wdt_stop(struct watchdog_device *wdev) { struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev); - pm_runtime_put(wdev->parent); reset_control_reset(priv->rstc); + pm_runtime_put(wdev->parent); return 0; } static int rzg2l_wdt_set_timeout(struct watchdog_device *wdev, unsigned int timeout) { - struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev); - wdev->timeout = timeout; /* * If the watchdog is active, reset the module for updating the WDTSET - * register so that it is updated with new timeout values. + * register by calling rzg2l_wdt_stop() (which internally calls reset_control_reset() + * to reset the module) so that it is updated with new timeout values. */ if (watchdog_active(wdev)) { - pm_runtime_put(wdev->parent); - reset_control_reset(priv->rstc); + rzg2l_wdt_stop(wdev); rzg2l_wdt_start(wdev); } From 1bcf3a9846e8e09159ce656146a6f775649d0ea9 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Thu, 17 Nov 2022 11:49:07 +0000 Subject: [PATCH 055/201] watchdog: rzg2l_wdt: Handle TYPE-B reset for RZ/V2M [ Upstream commit f769f97917c1e756e12ff042a93f6e3167254b5b ] As per section 48.4 of the HW User Manual, IPs in the RZ/V2M SoC need either a TYPE-A reset sequence or a TYPE-B reset sequence. More specifically, the watchdog IP needs a TYPE-B reset sequence. If the proper reset sequence isn't implemented, then resetting IPs may lead to undesired behaviour. In the restart callback of the watchdog driver the reset has basically no effect on the desired funcionality, as the register writes following the reset happen before the IP manages to come out of reset. Implement the TYPE-B reset sequence in the watchdog driver to address the issues with the restart callback on RZ/V2M. Fixes: ec122fd94eeb ("watchdog: rzg2l_wdt: Add rzv2m support") Signed-off-by: Fabrizio Castro Reviewed-by: Guenter Roeck Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20221117114907.138583-3-fabrizio.castro.jz@renesas.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Sasha Levin --- drivers/watchdog/rzg2l_wdt.c | 37 +++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/drivers/watchdog/rzg2l_wdt.c b/drivers/watchdog/rzg2l_wdt.c index ceca42db0837..d404953d0e0f 100644 --- a/drivers/watchdog/rzg2l_wdt.c +++ b/drivers/watchdog/rzg2l_wdt.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,8 @@ #define F2CYCLE_NSEC(f) (1000000000 / (f)) +#define RZV2M_A_NSEC 730 + static bool nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, bool, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" @@ -51,11 +54,35 @@ struct rzg2l_wdt_priv { struct reset_control *rstc; unsigned long osc_clk_rate; unsigned long delay; + unsigned long minimum_assertion_period; struct clk *pclk; struct clk *osc_clk; enum rz_wdt_type devtype; }; +static int rzg2l_wdt_reset(struct rzg2l_wdt_priv *priv) +{ + int err, status; + + if (priv->devtype == WDT_RZV2M) { + /* WDT needs TYPE-B reset control */ + err = reset_control_assert(priv->rstc); + if (err) + return err; + ndelay(priv->minimum_assertion_period); + err = reset_control_deassert(priv->rstc); + if (err) + return err; + err = read_poll_timeout(reset_control_status, status, + status != 1, 0, 1000, false, + priv->rstc); + } else { + err = reset_control_reset(priv->rstc); + } + + return err; +} + static void rzg2l_wdt_wait_delay(struct rzg2l_wdt_priv *priv) { /* delay timer when change the setting register */ @@ -115,7 +142,7 @@ static int rzg2l_wdt_stop(struct watchdog_device *wdev) { struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev); - reset_control_reset(priv->rstc); + rzg2l_wdt_reset(priv); pm_runtime_put(wdev->parent); return 0; @@ -154,6 +181,7 @@ static int rzg2l_wdt_restart(struct watchdog_device *wdev, rzg2l_wdt_write(priv, PEEN_FORCE, PEEN); } else { /* RZ/V2M doesn't have parity error registers */ + rzg2l_wdt_reset(priv); wdev->timeout = 0; @@ -251,6 +279,13 @@ static int rzg2l_wdt_probe(struct platform_device *pdev) priv->devtype = (uintptr_t)of_device_get_match_data(dev); + if (priv->devtype == WDT_RZV2M) { + priv->minimum_assertion_period = RZV2M_A_NSEC + + 3 * F2CYCLE_NSEC(pclk_rate) + 5 * + max(F2CYCLE_NSEC(priv->osc_clk_rate), + F2CYCLE_NSEC(pclk_rate)); + } + pm_runtime_enable(&pdev->dev); priv->wdev.info = &rzg2l_wdt_ident; From 89c682e9d04c04e786c571442dc86475337f8dfa Mon Sep 17 00:00:00 2001 From: ruanjinjie Date: Wed, 16 Nov 2022 17:49:50 +0800 Subject: [PATCH 056/201] watchdog: at91sam9_wdt: use devm_request_irq to avoid missing free_irq() in error path [ Upstream commit 07bec0e09c1afbab4c5674fd2341f4f52d594f30 ] free_irq() is missing in case of error in at91_wdt_init(), use devm_request_irq to fix that. Fixes: 5161b31dc39a ("watchdog: at91sam9_wdt: better watchdog support") Signed-off-by: ruanjinjie Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20221116094950.3141943-1-ruanjinjie@huawei.com [groeck: Adjust multi-line alignment] Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Sasha Levin --- drivers/watchdog/at91sam9_wdt.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c index 292b5a1ca831..fed7be246442 100644 --- a/drivers/watchdog/at91sam9_wdt.c +++ b/drivers/watchdog/at91sam9_wdt.c @@ -206,10 +206,9 @@ static int at91_wdt_init(struct platform_device *pdev, struct at91wdt *wdt) "min heartbeat and max heartbeat might be too close for the system to handle it correctly\n"); if ((tmp & AT91_WDT_WDFIEN) && wdt->irq) { - err = request_irq(wdt->irq, wdt_interrupt, - IRQF_SHARED | IRQF_IRQPOLL | - IRQF_NO_SUSPEND, - pdev->name, wdt); + err = devm_request_irq(dev, wdt->irq, wdt_interrupt, + IRQF_SHARED | IRQF_IRQPOLL | IRQF_NO_SUSPEND, + pdev->name, wdt); if (err) return err; } From ac099d94e0480c937aa9172ab64074981ca1a4d3 Mon Sep 17 00:00:00 2001 From: Chen Jun Date: Wed, 16 Nov 2022 01:27:14 +0000 Subject: [PATCH 057/201] watchdog: Fix kmemleak in watchdog_cdev_register [ Upstream commit 13721a2ac66b246f5802ba1b75ad8637e53eeecc ] kmemleak reports memory leaks in watchdog_dev_register, as follows: unreferenced object 0xffff888116233000 (size 2048): comm ""modprobe"", pid 28147, jiffies 4353426116 (age 61.741s) hex dump (first 32 bytes): 80 fa b9 05 81 88 ff ff 08 30 23 16 81 88 ff ff .........0#..... 08 30 23 16 81 88 ff ff 00 00 00 00 00 00 00 00 .0#............. backtrace: [<000000007f001ffd>] __kmem_cache_alloc_node+0x157/0x220 [<000000006a389304>] kmalloc_trace+0x21/0x110 [<000000008d640eea>] watchdog_dev_register+0x4e/0x780 [watchdog] [<0000000053c9f248>] __watchdog_register_device+0x4f0/0x680 [watchdog] [<00000000b2979824>] watchdog_register_device+0xd2/0x110 [watchdog] [<000000001f730178>] 0xffffffffc10880ae [<000000007a1a8bcc>] do_one_initcall+0xcb/0x4d0 [<00000000b98be325>] do_init_module+0x1ca/0x5f0 [<0000000046d08e7c>] load_module+0x6133/0x70f0 ... unreferenced object 0xffff888105b9fa80 (size 16): comm ""modprobe"", pid 28147, jiffies 4353426116 (age 61.741s) hex dump (first 16 bytes): 77 61 74 63 68 64 6f 67 31 00 b9 05 81 88 ff ff watchdog1....... backtrace: [<000000007f001ffd>] __kmem_cache_alloc_node+0x157/0x220 [<00000000486ab89b>] __kmalloc_node_track_caller+0x44/0x1b0 [<000000005a39aab0>] kvasprintf+0xb5/0x140 [<0000000024806f85>] kvasprintf_const+0x55/0x180 [<000000009276cb7f>] kobject_set_name_vargs+0x56/0x150 [<00000000a92e820b>] dev_set_name+0xab/0xe0 [<00000000cec812c6>] watchdog_dev_register+0x285/0x780 [watchdog] [<0000000053c9f248>] __watchdog_register_device+0x4f0/0x680 [watchdog] [<00000000b2979824>] watchdog_register_device+0xd2/0x110 [watchdog] [<000000001f730178>] 0xffffffffc10880ae [<000000007a1a8bcc>] do_one_initcall+0xcb/0x4d0 [<00000000b98be325>] do_init_module+0x1ca/0x5f0 [<0000000046d08e7c>] load_module+0x6133/0x70f0 ... The reason is that put_device is not be called if cdev_device_add fails and wdd->id != 0. watchdog_cdev_register wd_data = kzalloc [1] err = dev_set_name [2] .. err = cdev_device_add if (err) { if (wdd->id == 0) { // wdd->id != 0 .. } return err; // [1],[2] would be leaked To fix it, call put_device in all wdd->id cases. Fixes: 72139dfa2464 ("watchdog: Fix the race between the release of watchdog_core_data and cdev") Signed-off-by: Chen Jun Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20221116012714.102066-1-chenjun102@huawei.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Sasha Levin --- drivers/watchdog/watchdog_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c index 55574ed42504..fdffa6859dde 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c @@ -1061,8 +1061,8 @@ static int watchdog_cdev_register(struct watchdog_device *wdd) if (wdd->id == 0) { misc_deregister(&watchdog_miscdev); old_wd_data = NULL; - put_device(&wd_data->dev); } + put_device(&wd_data->dev); return err; } From ce64f72e988b0995e502ae8134d3954b669a273b Mon Sep 17 00:00:00 2001 From: Li Hua Date: Wed, 16 Nov 2022 10:07:06 +0800 Subject: [PATCH 058/201] watchdog: pcwd_usb: Fix attempting to access uninitialized memory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 7d06c07c67100fd0f8e6b3ab7145ce789f788117 ] The stack variable msb and lsb may be used uninitialized in function usb_pcwd_get_temperature and usb_pcwd_get_timeleft when usb card no response. The build waring is: drivers/watchdog/pcwd_usb.c:336:22: error: ‘lsb’ is used uninitialized in this function [-Werror=uninitialized] *temperature = (lsb * 9 / 5) + 32; ~~~~^~~ drivers/watchdog/pcwd_usb.c:328:21: note: ‘lsb’ was declared here unsigned char msb, lsb; ^~~ cc1: all warnings being treated as errors scripts/Makefile.build:250: recipe for target 'drivers/watchdog/pcwd_usb.o' failed make[3]: *** [drivers/watchdog/pcwd_usb.o] Error 1 Fixes: b7e04f8c61a4 ("mv watchdog tree under drivers") Signed-off-by: Li Hua Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20221116020706.70847-1-hucool.lihua@huawei.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Sasha Levin --- drivers/watchdog/pcwd_usb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/pcwd_usb.c b/drivers/watchdog/pcwd_usb.c index 1bdaf17c1d38..8202f0a6b093 100644 --- a/drivers/watchdog/pcwd_usb.c +++ b/drivers/watchdog/pcwd_usb.c @@ -325,7 +325,8 @@ static int usb_pcwd_set_heartbeat(struct usb_pcwd_private *usb_pcwd, int t) static int usb_pcwd_get_temperature(struct usb_pcwd_private *usb_pcwd, int *temperature) { - unsigned char msb, lsb; + unsigned char msb = 0x00; + unsigned char lsb = 0x00; usb_pcwd_send_command(usb_pcwd, CMD_READ_TEMP, &msb, &lsb); @@ -341,7 +342,8 @@ static int usb_pcwd_get_temperature(struct usb_pcwd_private *usb_pcwd, static int usb_pcwd_get_timeleft(struct usb_pcwd_private *usb_pcwd, int *time_left) { - unsigned char msb, lsb; + unsigned char msb = 0x00; + unsigned char lsb = 0x00; /* Read the time that's left before rebooting */ /* Note: if the board is not yet armed then we will read 0xFFFF */ From 12a91ade681b309d1acd27d84a9e5d56ffb92c3a Mon Sep 17 00:00:00 2001 From: George Cherian Date: Thu, 9 Feb 2023 02:11:17 +0000 Subject: [PATCH 059/201] watchdog: sbsa_wdog: Make sure the timeout programming is within the limits [ Upstream commit 000987a38b53c172f435142a4026dd71378ca464 ] Make sure to honour the max_hw_heartbeat_ms while programming the timeout value to WOR. Clamp the timeout passed to sbsa_gwdt_set_timeout() to make sure the programmed value is within the permissible range. Fixes: abd3ac7902fb ("watchdog: sbsa: Support architecture version 1") Signed-off-by: George Cherian Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20230209021117.1512097-1-george.cherian@marvell.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Sasha Levin --- drivers/watchdog/sbsa_gwdt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c index 9791c74aebd4..63862803421f 100644 --- a/drivers/watchdog/sbsa_gwdt.c +++ b/drivers/watchdog/sbsa_gwdt.c @@ -150,6 +150,7 @@ static int sbsa_gwdt_set_timeout(struct watchdog_device *wdd, struct sbsa_gwdt *gwdt = watchdog_get_drvdata(wdd); wdd->timeout = timeout; + timeout = clamp_t(unsigned int, timeout, 1, wdd->max_hw_heartbeat_ms / 1000); if (action) sbsa_gwdt_reg_write(gwdt->clk * timeout, gwdt); From 4f25d1dff80535f088b8f8568dd731fb098e29b4 Mon Sep 17 00:00:00 2001 From: Hangyu Hua Date: Fri, 10 Feb 2023 15:17:30 +0800 Subject: [PATCH 060/201] netfilter: ctnetlink: fix possible refcount leak in ctnetlink_create_conntrack() [ Upstream commit ac4893980bbe79ce383daf9a0885666a30fe4c83 ] nf_ct_put() needs to be called to put the refcount got by nf_conntrack_find_get() to avoid refcount leak when nf_conntrack_hash_check_insert() fails. Fixes: 7d367e06688d ("netfilter: ctnetlink: fix soft lockup when netlink adds new entries (v2)") Signed-off-by: Hangyu Hua Acked-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- net/netfilter/nf_conntrack_netlink.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 1286ae7d4609..ca4d5bb1ea52 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -2375,12 +2375,15 @@ ctnetlink_create_conntrack(struct net *net, err = nf_conntrack_hash_check_insert(ct); if (err < 0) - goto err2; + goto err3; rcu_read_unlock(); return ct; +err3: + if (ct->master) + nf_ct_put(ct->master); err2: rcu_read_unlock(); err1: From 1fd3c69f6511cc0785d5f5f828a5c095d74df69f Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 14 Feb 2023 17:23:59 +0100 Subject: [PATCH 061/201] netfilter: conntrack: fix rmmod double-free race [ Upstream commit e6d57e9ff0aec323717ee36fc9ea34ad89217151 ] nf_conntrack_hash_check_insert() callers free the ct entry directly, via nf_conntrack_free. This isn't safe anymore because nf_conntrack_hash_check_insert() might place the entry into the conntrack table and then delteted the entry again because it found that a conntrack extension has been removed at the same time. In this case, the just-added entry is removed again and an error is returned to the caller. Problem is that another cpu might have picked up this entry and incremented its reference count. This results in a use-after-free/double-free, once by the other cpu and once by the caller of nf_conntrack_hash_check_insert(). Fix this by making nf_conntrack_hash_check_insert() not fail anymore after the insertion, just like before the 'Fixes' commit. This is safe because a racing nf_ct_iterate() has to wait for us to release the conntrack hash spinlocks. While at it, make the function return -EAGAIN in the rmmod (genid changed) case, this makes nfnetlink replay the command (suggested by Pablo Neira). Fixes: c56716c69ce1 ("netfilter: extensions: introduce extension genid count") Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- net/netfilter/nf_conntrack_bpf.c | 1 - net/netfilter/nf_conntrack_core.c | 25 +++++++++++++++---------- net/netfilter/nf_conntrack_netlink.c | 3 --- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/net/netfilter/nf_conntrack_bpf.c b/net/netfilter/nf_conntrack_bpf.c index 8639e7efd0e2..adae86e8e02e 100644 --- a/net/netfilter/nf_conntrack_bpf.c +++ b/net/netfilter/nf_conntrack_bpf.c @@ -384,7 +384,6 @@ struct nf_conn *bpf_ct_insert_entry(struct nf_conn___init *nfct_i) struct nf_conn *nfct = (struct nf_conn *)nfct_i; int err; - nfct->status |= IPS_CONFIRMED; err = nf_conntrack_hash_check_insert(nfct); if (err < 0) { nf_conntrack_free(nfct); diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 23b3fedd619a..7f0f3bcaae03 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -890,10 +890,8 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct) zone = nf_ct_zone(ct); - if (!nf_ct_ext_valid_pre(ct->ext)) { - NF_CT_STAT_INC_ATOMIC(net, insert_failed); - return -ETIMEDOUT; - } + if (!nf_ct_ext_valid_pre(ct->ext)) + return -EAGAIN; local_bh_disable(); do { @@ -928,6 +926,19 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct) goto chaintoolong; } + /* If genid has changed, we can't insert anymore because ct + * extensions could have stale pointers and nf_ct_iterate_destroy + * might have completed its table scan already. + * + * Increment of the ext genid right after this check is fine: + * nf_ct_iterate_destroy blocks until locks are released. + */ + if (!nf_ct_ext_valid_post(ct->ext)) { + err = -EAGAIN; + goto out; + } + + ct->status |= IPS_CONFIRMED; smp_wmb(); /* The caller holds a reference to this object */ refcount_set(&ct->ct_general.use, 2); @@ -936,12 +947,6 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct) NF_CT_STAT_INC(net, insert); local_bh_enable(); - if (!nf_ct_ext_valid_post(ct->ext)) { - nf_ct_kill(ct); - NF_CT_STAT_INC_ATOMIC(net, drop); - return -ETIMEDOUT; - } - return 0; chaintoolong: NF_CT_STAT_INC(net, chaintoolong); diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index ca4d5bb1ea52..733bb56950c1 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -2316,9 +2316,6 @@ ctnetlink_create_conntrack(struct net *net, nfct_seqadj_ext_add(ct); nfct_synproxy_ext_add(ct); - /* we must add conntrack extensions before confirmation. */ - ct->status |= IPS_CONFIRMED; - if (cda[CTA_STATUS]) { err = ctnetlink_change_status(ct, cda); if (err < 0) From 8291cfdfa6cd5eacfe1a5ba81b1a8cea4f086366 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 16 Feb 2023 17:05:36 +0100 Subject: [PATCH 062/201] netfilter: ip6t_rpfilter: Fix regression with VRF interfaces [ Upstream commit efb056e5f1f0036179b2f92c1c15f5ea7a891d70 ] When calling ip6_route_lookup() for the packet arriving on the VRF interface, the result is always the real (slave) interface. Expect this when validating the result. Fixes: acc641ab95b66 ("netfilter: rpfilter/fib: Populate flowic_l3mdev field") Signed-off-by: Phil Sutter Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- net/ipv6/netfilter/ip6t_rpfilter.c | 4 ++- tools/testing/selftests/netfilter/rpath.sh | 32 ++++++++++++++++++---- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/net/ipv6/netfilter/ip6t_rpfilter.c b/net/ipv6/netfilter/ip6t_rpfilter.c index a01d9b842bd0..67c87a88cde4 100644 --- a/net/ipv6/netfilter/ip6t_rpfilter.c +++ b/net/ipv6/netfilter/ip6t_rpfilter.c @@ -72,7 +72,9 @@ static bool rpfilter_lookup_reverse6(struct net *net, const struct sk_buff *skb, goto out; } - if (rt->rt6i_idev->dev == dev || (flags & XT_RPFILTER_LOOSE)) + if (rt->rt6i_idev->dev == dev || + l3mdev_master_ifindex_rcu(rt->rt6i_idev->dev) == dev->ifindex || + (flags & XT_RPFILTER_LOOSE)) ret = true; out: ip6_rt_put(rt); diff --git a/tools/testing/selftests/netfilter/rpath.sh b/tools/testing/selftests/netfilter/rpath.sh index f7311e66d219..5289c8447a41 100755 --- a/tools/testing/selftests/netfilter/rpath.sh +++ b/tools/testing/selftests/netfilter/rpath.sh @@ -62,10 +62,16 @@ ip -net "$ns1" a a fec0:42::2/64 dev v0 nodad ip -net "$ns2" a a fec0:42::1/64 dev d0 nodad # firewall matches to test -[ -n "$iptables" ] && ip netns exec "$ns2" \ - "$iptables" -t raw -A PREROUTING -s 192.168.0.0/16 -m rpfilter -[ -n "$ip6tables" ] && ip netns exec "$ns2" \ - "$ip6tables" -t raw -A PREROUTING -s fec0::/16 -m rpfilter +[ -n "$iptables" ] && { + common='-t raw -A PREROUTING -s 192.168.0.0/16' + ip netns exec "$ns2" "$iptables" $common -m rpfilter + ip netns exec "$ns2" "$iptables" $common -m rpfilter --invert +} +[ -n "$ip6tables" ] && { + common='-t raw -A PREROUTING -s fec0::/16' + ip netns exec "$ns2" "$ip6tables" $common -m rpfilter + ip netns exec "$ns2" "$ip6tables" $common -m rpfilter --invert +} [ -n "$nft" ] && ip netns exec "$ns2" $nft -f - </dev/null } -testrun() { - # clear counters first +clear_counters() { [ -n "$iptables" ] && ip netns exec "$ns2" "$iptables" -t raw -Z [ -n "$ip6tables" ] && ip netns exec "$ns2" "$ip6tables" -t raw -Z if [ -n "$nft" ]; then @@ -111,6 +121,10 @@ testrun() { ip netns exec "$ns2" $nft -s list table inet t; ) | ip netns exec "$ns2" $nft -f - fi +} + +testrun() { + clear_counters # test 1: martian traffic should fail rpfilter matches netns_ping "$ns1" -I v0 192.168.42.1 && \ @@ -120,9 +134,13 @@ testrun() { ipt_zero_rule "$iptables" || die "iptables matched martian" ipt_zero_rule "$ip6tables" || die "ip6tables matched martian" + ipt_zero_reverse_rule "$iptables" && die "iptables not matched martian" + ipt_zero_reverse_rule "$ip6tables" && die "ip6tables not matched martian" nft_zero_rule ip || die "nft IPv4 matched martian" nft_zero_rule ip6 || die "nft IPv6 matched martian" + clear_counters + # test 2: rpfilter match should pass for regular traffic netns_ping "$ns1" 192.168.23.1 || \ die "regular ping 192.168.23.1 failed" @@ -131,6 +149,8 @@ testrun() { ipt_zero_rule "$iptables" && die "iptables match not effective" ipt_zero_rule "$ip6tables" && die "ip6tables match not effective" + ipt_zero_reverse_rule "$iptables" || die "iptables match over-effective" + ipt_zero_reverse_rule "$ip6tables" || die "ip6tables match over-effective" nft_zero_rule ip && die "nft IPv4 match not effective" nft_zero_rule ip6 && die "nft IPv6 match not effective" From 3dd6ac973351308d4117eda32298a9f1d68764fd Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 17 Feb 2023 23:20:06 +0100 Subject: [PATCH 063/201] netfilter: ebtables: fix table blob use-after-free [ Upstream commit e58a171d35e32e6e8c37cfe0e8a94406732a331f ] We are not allowed to return an error at this point. Looking at the code it looks like ret is always 0 at this point, but its not. t = find_table_lock(net, repl->name, &ret, &ebt_mutex); ... this can return a valid table, with ret != 0. This bug causes update of table->private with the new blob, but then frees the blob right away in the caller. Syzbot report: BUG: KASAN: vmalloc-out-of-bounds in __ebt_unregister_table+0xc00/0xcd0 net/bridge/netfilter/ebtables.c:1168 Read of size 4 at addr ffffc90005425000 by task kworker/u4:4/74 Workqueue: netns cleanup_net Call Trace: kasan_report+0xbf/0x1f0 mm/kasan/report.c:517 __ebt_unregister_table+0xc00/0xcd0 net/bridge/netfilter/ebtables.c:1168 ebt_unregister_table+0x35/0x40 net/bridge/netfilter/ebtables.c:1372 ops_exit_list+0xb0/0x170 net/core/net_namespace.c:169 cleanup_net+0x4ee/0xb10 net/core/net_namespace.c:613 ... ip(6)tables appears to be ok (ret should be 0 at this point) but make this more obvious. Fixes: c58dd2dd443c ("netfilter: Can't fail and free after table replacement") Reported-by: syzbot+f61594de72d6705aea03@syzkaller.appspotmail.com Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- net/bridge/netfilter/ebtables.c | 2 +- net/ipv4/netfilter/ip_tables.c | 3 +-- net/ipv6/netfilter/ip6_tables.c | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index ce5dfa3babd2..757ec46fc45a 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -1090,7 +1090,7 @@ static int do_replace_finish(struct net *net, struct ebt_replace *repl, audit_log_nfcfg(repl->name, AF_BRIDGE, repl->nentries, AUDIT_XT_OP_REPLACE, GFP_KERNEL); - return ret; + return 0; free_unlock: mutex_unlock(&ebt_mutex); diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 2ed7c58b471a..aae5fd51dfd7 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -1045,7 +1045,6 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, struct xt_counters *counters; struct ipt_entry *iter; - ret = 0; counters = xt_counters_alloc(num_counters); if (!counters) { ret = -ENOMEM; @@ -1091,7 +1090,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, net_warn_ratelimited("iptables: counters copy to user failed while replacing table\n"); } vfree(counters); - return ret; + return 0; put_module: module_put(t->me); diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 2d816277f2c5..ac902f7bca47 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -1062,7 +1062,6 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, struct xt_counters *counters; struct ip6t_entry *iter; - ret = 0; counters = xt_counters_alloc(num_counters); if (!counters) { ret = -ENOMEM; @@ -1108,7 +1107,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, net_warn_ratelimited("ip6tables: counters copy to user failed while replacing table\n"); } vfree(counters); - return ret; + return 0; put_module: module_put(t->me); From f2ccb36b8f76a970ac325f8c64c1d658933f8868 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Fri, 17 Feb 2023 18:22:57 -0500 Subject: [PATCH 064/201] netfilter: xt_length: use skb len to match in length_mt6 [ Upstream commit 05c07c0c6cc8ec2278ace9871618c41f1365d1f5 ] For IPv6 Jumbo packets, the ipv6_hdr(skb)->payload_len is always 0, and its real payload_len ( > 65535) is saved in hbh exthdr. With 0 length for the jumbo packets, it may mismatch. To fix this, we can just use skb->len instead of parsing exthdrs, as the hbh exthdr parsing has been done before coming to length_mt6 in ip6_rcv_core() and br_validate_ipv6() and also the packet has been trimmed according to the correct IPv6 (ext)hdr length there, and skb len is trustable in length_mt6(). Note that this patch is especially needed after the IPv6 BIG TCP was supported in kernel, which is using IPv6 Jumbo packets. Besides, to match the packets greater than 65535 more properly, a v1 revision of xt_length may be needed to extend "min, max" to u32 in the future, and for now the IPv6 Jumbo packets can be matched by: # ip6tables -m length ! --length 0:65535 Fixes: 7c4e983c4f3c ("net: allow gso_max_size to exceed 65536") Fixes: 0fe79f28bfaf ("net: allow gro_max_size to exceed 65536") Signed-off-by: Xin Long Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- net/netfilter/xt_length.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/netfilter/xt_length.c b/net/netfilter/xt_length.c index 1873da3a945a..9fbfad13176f 100644 --- a/net/netfilter/xt_length.c +++ b/net/netfilter/xt_length.c @@ -30,8 +30,7 @@ static bool length_mt6(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_length_info *info = par->matchinfo; - const u_int16_t pktlen = ntohs(ipv6_hdr(skb)->payload_len) + - sizeof(struct ipv6hdr); + u32 pktlen = skb->len; return (pktlen >= info->min && pktlen <= info->max) ^ info->invert; } From ffba2d57902646bdf9b8e16fd09f7d63a12f7941 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 20 Feb 2023 17:24:00 +0100 Subject: [PATCH 065/201] netfilter: ctnetlink: make event listener tracking global [ Upstream commit fdf6491193e411087ae77bcbc6468e3e1cff99ed ] pernet tracking doesn't work correctly because other netns might have set NETLINK_LISTEN_ALL_NSID on its event socket. In this case its expected that events originating in other net namespaces are also received. Making pernet-tracking work while also honoring NETLINK_LISTEN_ALL_NSID requires much more intrusive changes both in netlink and nfnetlink, f.e. adding a 'setsockopt' callback that lets nfnetlink know that the event socket entered (or left) ALL_NSID mode. Move to global tracking instead: if there is an event socket anywhere on the system, all net namespaces which have conntrack enabled and use autobind mode will allocate the ecache extension. netlink_has_listeners() returns false only if the given group has no subscribers in any net namespace, the 'net' argument passed to nfnetlink_has_listeners is only used to derive the protocol (nfnetlink), it has no other effect. For proper NETLINK_LISTEN_ALL_NSID-aware pernet tracking of event listeners a new netlink_has_net_listeners() is also needed. Fixes: 90d1daa45849 ("netfilter: conntrack: add nf_conntrack_events autodetect mode") Reported-by: Bryce Kahle Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- include/linux/netfilter.h | 5 +++++ include/net/netns/conntrack.h | 1 - net/netfilter/core.c | 3 +++ net/netfilter/nf_conntrack_ecache.c | 2 +- net/netfilter/nfnetlink.c | 9 +++++---- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index d8817d381c14..bef8db9d6c08 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -488,4 +488,9 @@ extern const struct nfnl_ct_hook __rcu *nfnl_ct_hook; */ DECLARE_PER_CPU(bool, nf_skb_duplicated); +/** + * Contains bitmask of ctnetlink event subscribers, if any. + * Can't be pernet due to NETLINK_LISTEN_ALL_NSID setsockopt flag. + */ +extern u8 nf_ctnetlink_has_listener; #endif /*__LINUX_NETFILTER_H*/ diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h index e1290c159184..1f463b3957c7 100644 --- a/include/net/netns/conntrack.h +++ b/include/net/netns/conntrack.h @@ -95,7 +95,6 @@ struct nf_ip_net { struct netns_ct { #ifdef CONFIG_NF_CONNTRACK_EVENTS - u8 ctnetlink_has_listener; bool ecache_dwork_pending; #endif u8 sysctl_log_invalid; /* Log invalid packets */ diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 5a6705a0e4ec..6e80f0f6149e 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -669,6 +669,9 @@ const struct nf_ct_hook __rcu *nf_ct_hook __read_mostly; EXPORT_SYMBOL_GPL(nf_ct_hook); #if IS_ENABLED(CONFIG_NF_CONNTRACK) +u8 nf_ctnetlink_has_listener; +EXPORT_SYMBOL_GPL(nf_ctnetlink_has_listener); + const struct nf_nat_hook __rcu *nf_nat_hook __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_hook); diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c index 8698b3424646..69948e1d6974 100644 --- a/net/netfilter/nf_conntrack_ecache.c +++ b/net/netfilter/nf_conntrack_ecache.c @@ -309,7 +309,7 @@ bool nf_ct_ecache_ext_add(struct nf_conn *ct, u16 ctmask, u16 expmask, gfp_t gfp break; return true; case 2: /* autodetect: no event listener, don't allocate extension. */ - if (!READ_ONCE(net->ct.ctnetlink_has_listener)) + if (!READ_ONCE(nf_ctnetlink_has_listener)) return true; fallthrough; case 1: diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index 6d18fb346868..81c7737c803a 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -29,6 +29,7 @@ #include #include +#include #include MODULE_LICENSE("GPL"); @@ -685,12 +686,12 @@ static void nfnetlink_bind_event(struct net *net, unsigned int group) group_bit = (1 << group); spin_lock(&nfnl_grp_active_lock); - v = READ_ONCE(net->ct.ctnetlink_has_listener); + v = READ_ONCE(nf_ctnetlink_has_listener); if ((v & group_bit) == 0) { v |= group_bit; /* read concurrently without nfnl_grp_active_lock held. */ - WRITE_ONCE(net->ct.ctnetlink_has_listener, v); + WRITE_ONCE(nf_ctnetlink_has_listener, v); } spin_unlock(&nfnl_grp_active_lock); @@ -744,12 +745,12 @@ static void nfnetlink_unbind(struct net *net, int group) spin_lock(&nfnl_grp_active_lock); if (!nfnetlink_has_listeners(net, group)) { - u8 v = READ_ONCE(net->ct.ctnetlink_has_listener); + u8 v = READ_ONCE(nf_ctnetlink_has_listener); v &= ~group_bit; /* read concurrently without nfnl_grp_active_lock held. */ - WRITE_ONCE(net->ct.ctnetlink_has_listener, v); + WRITE_ONCE(nf_ctnetlink_has_listener, v); } spin_unlock(&nfnl_grp_active_lock); #endif From 512b6c4b83c91d007301ea7d7f095d16c3aceacd Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Mon, 13 Feb 2023 12:25:05 +0800 Subject: [PATCH 066/201] netfilter: x_tables: fix percpu counter block leak on error path when creating new netns [ Upstream commit 0af8c09c896810879387decfba8c942994bb61f5 ] Here is the stack where we allocate percpu counter block: +-< __alloc_percpu +-< xt_percpu_counter_alloc +-< find_check_entry # {arp,ip,ip6}_tables.c +-< translate_table And it can be leaked on this code path: +-> ip6t_register_table +-> translate_table # allocates percpu counter block +-> xt_register_table # fails there is no freeing of the counter block on xt_register_table fail. Note: xt_percpu_counter_free should be called to free it like we do in do_replace through cleanup_entry helper (or in __ip6t_unregister_table). Probability of hitting this error path is low AFAICS (xt_register_table can only return ENOMEM here, as it is not replacing anything, as we are creating new netns, and it is hard to imagine that all previous allocations succeeded and after that one in xt_register_table failed). But it's worth fixing even the rare leak. Fixes: 71ae0dff02d7 ("netfilter: xtables: use percpu rule counters") Signed-off-by: Pavel Tikhomirov Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- net/ipv4/netfilter/arp_tables.c | 4 ++++ net/ipv4/netfilter/ip_tables.c | 4 ++++ net/ipv6/netfilter/ip6_tables.c | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index ffc0cab7cf18..2407066b0fec 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -1525,6 +1525,10 @@ int arpt_register_table(struct net *net, new_table = xt_register_table(net, table, &bootstrap, newinfo); if (IS_ERR(new_table)) { + struct arpt_entry *iter; + + xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) + cleanup_entry(iter, net); xt_free_table_info(newinfo); return PTR_ERR(new_table); } diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index aae5fd51dfd7..da5998011ab9 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -1741,6 +1741,10 @@ int ipt_register_table(struct net *net, const struct xt_table *table, new_table = xt_register_table(net, table, &bootstrap, newinfo); if (IS_ERR(new_table)) { + struct ipt_entry *iter; + + xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) + cleanup_entry(iter, net); xt_free_table_info(newinfo); return PTR_ERR(new_table); } diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index ac902f7bca47..0ce0ed17c758 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -1750,6 +1750,10 @@ int ip6t_register_table(struct net *net, const struct xt_table *table, new_table = xt_register_table(net, table, &bootstrap, newinfo); if (IS_ERR(new_table)) { + struct ip6t_entry *iter; + + xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) + cleanup_entry(iter, net); xt_free_table_info(newinfo); return PTR_ERR(new_table); } From f94becae90b04b2d1580548d8cd70653eb8dfb17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8D=C3=B1igo=20Huguet?= Date: Tue, 21 Feb 2023 14:06:16 +0100 Subject: [PATCH 067/201] ptp: vclock: use mutex to fix "sleep on atomic" bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 67d93ffc0f3c47094750bde6d62e7c5765dc47a6 ] vclocks were using spinlocks to protect access to its timecounter and cyclecounter. Access to timecounter/cyclecounter is backed by the same driver callbacks that are used for non-virtual PHCs, but the usage of the spinlock imposes a new limitation that didn't exist previously: now they're called in atomic context so they mustn't sleep. Some drivers like sfc or ice may sleep on these callbacks, causing errors like "BUG: scheduling while atomic: ptp5/25223/0x00000002" Fix it replacing the vclock's spinlock by a mutex. It fix the mentioned bug and it doesn't introduce longer delays. I've tested synchronizing various different combinations of clocks: - vclock->sysclock - sysclock->vclock - vclock->vclock - hardware PHC in different NIC -> vclock - created 4 vclocks and launch 4 parallel phc2sys processes with lockdep enabled In all cases, comparing the delays reported by phc2sys, they are in the same range of values than before applying the patch. Link: https://lore.kernel.org/netdev/69d0ff33-bd32-6aa5-d36c-fbdc3c01337c@redhat.com/ Fixes: 5d43f951b1ac ("ptp: add ptp virtual clock driver framework") Reported-by: Yalin Li Suggested-by: Richard Cochran Tested-by: Miroslav Lichvar Signed-off-by: Íñigo Huguet Acked-by: Richard Cochran Link: https://lore.kernel.org/r/20230221130616.21837-1-ihuguet@redhat.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/ptp/ptp_private.h | 2 +- drivers/ptp/ptp_vclock.c | 44 +++++++++++++++++++-------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/ptp/ptp_private.h b/drivers/ptp/ptp_private.h index 77918a2c6701..75f58fc468a7 100644 --- a/drivers/ptp/ptp_private.h +++ b/drivers/ptp/ptp_private.h @@ -66,7 +66,7 @@ struct ptp_vclock { struct hlist_node vclock_hash_node; struct cyclecounter cc; struct timecounter tc; - spinlock_t lock; /* protects tc/cc */ + struct mutex lock; /* protects tc/cc */ }; /* diff --git a/drivers/ptp/ptp_vclock.c b/drivers/ptp/ptp_vclock.c index 1c0ed4805c0a..dcf752c9e045 100644 --- a/drivers/ptp/ptp_vclock.c +++ b/drivers/ptp/ptp_vclock.c @@ -43,16 +43,16 @@ static void ptp_vclock_hash_del(struct ptp_vclock *vclock) static int ptp_vclock_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) { struct ptp_vclock *vclock = info_to_vclock(ptp); - unsigned long flags; s64 adj; adj = (s64)scaled_ppm << PTP_VCLOCK_FADJ_SHIFT; adj = div_s64(adj, PTP_VCLOCK_FADJ_DENOMINATOR); - spin_lock_irqsave(&vclock->lock, flags); + if (mutex_lock_interruptible(&vclock->lock)) + return -EINTR; timecounter_read(&vclock->tc); vclock->cc.mult = PTP_VCLOCK_CC_MULT + adj; - spin_unlock_irqrestore(&vclock->lock, flags); + mutex_unlock(&vclock->lock); return 0; } @@ -60,11 +60,11 @@ static int ptp_vclock_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) static int ptp_vclock_adjtime(struct ptp_clock_info *ptp, s64 delta) { struct ptp_vclock *vclock = info_to_vclock(ptp); - unsigned long flags; - spin_lock_irqsave(&vclock->lock, flags); + if (mutex_lock_interruptible(&vclock->lock)) + return -EINTR; timecounter_adjtime(&vclock->tc, delta); - spin_unlock_irqrestore(&vclock->lock, flags); + mutex_unlock(&vclock->lock); return 0; } @@ -73,12 +73,12 @@ static int ptp_vclock_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) { struct ptp_vclock *vclock = info_to_vclock(ptp); - unsigned long flags; u64 ns; - spin_lock_irqsave(&vclock->lock, flags); + if (mutex_lock_interruptible(&vclock->lock)) + return -EINTR; ns = timecounter_read(&vclock->tc); - spin_unlock_irqrestore(&vclock->lock, flags); + mutex_unlock(&vclock->lock); *ts = ns_to_timespec64(ns); return 0; @@ -91,7 +91,6 @@ static int ptp_vclock_gettimex(struct ptp_clock_info *ptp, struct ptp_vclock *vclock = info_to_vclock(ptp); struct ptp_clock *pptp = vclock->pclock; struct timespec64 pts; - unsigned long flags; int err; u64 ns; @@ -99,9 +98,10 @@ static int ptp_vclock_gettimex(struct ptp_clock_info *ptp, if (err) return err; - spin_lock_irqsave(&vclock->lock, flags); + if (mutex_lock_interruptible(&vclock->lock)) + return -EINTR; ns = timecounter_cyc2time(&vclock->tc, timespec64_to_ns(&pts)); - spin_unlock_irqrestore(&vclock->lock, flags); + mutex_unlock(&vclock->lock); *ts = ns_to_timespec64(ns); @@ -113,11 +113,11 @@ static int ptp_vclock_settime(struct ptp_clock_info *ptp, { struct ptp_vclock *vclock = info_to_vclock(ptp); u64 ns = timespec64_to_ns(ts); - unsigned long flags; - spin_lock_irqsave(&vclock->lock, flags); + if (mutex_lock_interruptible(&vclock->lock)) + return -EINTR; timecounter_init(&vclock->tc, &vclock->cc, ns); - spin_unlock_irqrestore(&vclock->lock, flags); + mutex_unlock(&vclock->lock); return 0; } @@ -127,7 +127,6 @@ static int ptp_vclock_getcrosststamp(struct ptp_clock_info *ptp, { struct ptp_vclock *vclock = info_to_vclock(ptp); struct ptp_clock *pptp = vclock->pclock; - unsigned long flags; int err; u64 ns; @@ -135,9 +134,10 @@ static int ptp_vclock_getcrosststamp(struct ptp_clock_info *ptp, if (err) return err; - spin_lock_irqsave(&vclock->lock, flags); + if (mutex_lock_interruptible(&vclock->lock)) + return -EINTR; ns = timecounter_cyc2time(&vclock->tc, ktime_to_ns(xtstamp->device)); - spin_unlock_irqrestore(&vclock->lock, flags); + mutex_unlock(&vclock->lock); xtstamp->device = ns_to_ktime(ns); @@ -205,7 +205,7 @@ struct ptp_vclock *ptp_vclock_register(struct ptp_clock *pclock) INIT_HLIST_NODE(&vclock->vclock_hash_node); - spin_lock_init(&vclock->lock); + mutex_init(&vclock->lock); vclock->clock = ptp_clock_register(&vclock->info, &pclock->dev); if (IS_ERR_OR_NULL(vclock->clock)) { @@ -269,7 +269,6 @@ ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, int vclock_index) { unsigned int hash = vclock_index % HASH_SIZE(vclock_hash); struct ptp_vclock *vclock; - unsigned long flags; u64 ns; u64 vclock_ns = 0; @@ -281,9 +280,10 @@ ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, int vclock_index) if (vclock->clock->index != vclock_index) continue; - spin_lock_irqsave(&vclock->lock, flags); + if (mutex_lock_interruptible(&vclock->lock)) + break; vclock_ns = timecounter_cyc2time(&vclock->tc, ns); - spin_unlock_irqrestore(&vclock->lock, flags); + mutex_unlock(&vclock->lock); break; } From b232d4e840ed68a1dddf208b7bf57c2dcc6cba2c Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 14 Feb 2023 20:45:33 -0800 Subject: [PATCH 068/201] drm/i915: move a Kconfig symbol to unbreak the menu presentation [ Upstream commit 0b93efca3659f6d55ed31cff6722dca5f6e4d6e2 ] Inserting a Kconfig symbol that does not have a dependency (DRM_I915_GVT) into a list of other symbols that do have a dependency (on DRM_I915) breaks the driver menu presentation in 'make *config'. Relocate the DRM_I915_GVT symbol so that it does not cause this problem. Fixes: 8b750bf74418 ("drm/i915/gvt: move the gvt code into kvmgt.ko") Signed-off-by: Randy Dunlap Cc: Christoph Hellwig Cc: Zhi Wang Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: Tvrtko Ursulin Cc: Zhenyu Wang Cc: intel-gfx@lists.freedesktop.org Cc: intel-gvt-dev@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org Reviewed-by: Christoph Hellwig Acked-by: Zhenyu Wang Signed-off-by: Zhenyu Wang Link: http://patchwork.freedesktop.org/patch/msgid/20230215044533.4847-1-rdunlap@infradead.org Signed-off-by: Sasha Levin --- drivers/gpu/drm/i915/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index 3efce05d7b57..3a6e176d77aa 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -107,9 +107,6 @@ config DRM_I915_USERPTR If in doubt, say "Y". -config DRM_I915_GVT - bool - config DRM_I915_GVT_KVMGT tristate "Enable KVM host support Intel GVT-g graphics virtualization" depends on DRM_I915 @@ -160,3 +157,6 @@ menu "drm/i915 Unstable Evolution" depends on DRM_I915 source "drivers/gpu/drm/i915/Kconfig.unstable" endmenu + +config DRM_I915_GVT + bool From e11e4d524eba2d3c8fdf897d7ce3853f7573bae9 Mon Sep 17 00:00:00 2001 From: Lu Wei Date: Wed, 22 Feb 2023 16:36:28 +0800 Subject: [PATCH 069/201] ipv6: Add lwtunnel encap size of all siblings in nexthop calculation [ Upstream commit 4cc59f386991ec9374cb4bc83dbe1c0b5a95033f ] In function rt6_nlmsg_size(), the length of nexthop is calculated by multipling the nexthop length of fib6_info and the number of siblings. However if the fib6_info has no lwtunnel but the siblings have lwtunnels, the nexthop length is less than it should be, and it will trigger a warning in inet6_rt_notify() as follows: WARNING: CPU: 0 PID: 6082 at net/ipv6/route.c:6180 inet6_rt_notify+0x120/0x130 ...... Call Trace: fib6_add_rt2node+0x685/0xa30 fib6_add+0x96/0x1b0 ip6_route_add+0x50/0xd0 inet6_rtm_newroute+0x97/0xa0 rtnetlink_rcv_msg+0x156/0x3d0 netlink_rcv_skb+0x5a/0x110 netlink_unicast+0x246/0x350 netlink_sendmsg+0x250/0x4c0 sock_sendmsg+0x66/0x70 ___sys_sendmsg+0x7c/0xd0 __sys_sendmsg+0x5d/0xb0 do_syscall_64+0x3f/0x90 entry_SYSCALL_64_after_hwframe+0x72/0xdc This bug can be reproduced by script: ip -6 addr add 2002::2/64 dev ens2 ip -6 route add 100::/64 via 2002::1 dev ens2 metric 100 for i in 10 20 30 40 50 60 70; do ip link add link ens2 name ipv_$i type ipvlan ip -6 addr add 2002::$i/64 dev ipv_$i ifconfig ipv_$i up done for i in 10 20 30 40 50 60; do ip -6 route append 100::/64 encap ip6 dst 2002::$i via 2002::1 dev ipv_$i metric 100 done ip -6 route append 100::/64 via 2002::1 dev ipv_70 metric 100 This patch fixes it by adding nexthop_len of every siblings using rt6_nh_nlmsg_size(). Fixes: beb1afac518d ("net: ipv6: Add support to dump multipath routes via RTA_MULTIPATH attribute") Signed-off-by: Lu Wei Reviewed-by: David Ahern Link: https://lore.kernel.org/r/20230222083629.335683-2-luwei32@huawei.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- net/ipv6/route.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 2f355f0ec32a..0b060cb8681f 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -5540,16 +5540,17 @@ static size_t rt6_nlmsg_size(struct fib6_info *f6i) nexthop_for_each_fib6_nh(f6i->nh, rt6_nh_nlmsg_size, &nexthop_len); } else { + struct fib6_info *sibling, *next_sibling; struct fib6_nh *nh = f6i->fib6_nh; nexthop_len = 0; if (f6i->fib6_nsiblings) { - nexthop_len = nla_total_size(0) /* RTA_MULTIPATH */ - + NLA_ALIGN(sizeof(struct rtnexthop)) - + nla_total_size(16) /* RTA_GATEWAY */ - + lwtunnel_get_encap_size(nh->fib_nh_lws); + rt6_nh_nlmsg_size(nh, &nexthop_len); - nexthop_len *= f6i->fib6_nsiblings; + list_for_each_entry_safe(sibling, next_sibling, + &f6i->fib6_siblings, fib6_siblings) { + rt6_nh_nlmsg_size(sibling->fib6_nh, &nexthop_len); + } } nexthop_len += lwtunnel_get_encap_size(nh->fib_nh_lws); } From e3aa5d1bb1b2bdc6e0649d27b7eaa02d03f5f040 Mon Sep 17 00:00:00 2001 From: Geetha sowjanya Date: Wed, 22 Feb 2023 17:06:00 +0530 Subject: [PATCH 070/201] octeontx2-pf: Recalculate UDP checksum for ptp 1-step sync packet [ Upstream commit edea0c5a994b7829c9ada8f5bc762c4e32f4f797 ] When checksum offload is disabled in the driver via ethtool, the PTP 1-step sync packets contain incorrect checksum, since the stack calculates the checksum before driver updates PTP timestamp field in the packet. This results in PTP packets getting dropped at the other end. This patch fixes the issue by re-calculating the UDP checksum after updating PTP timestamp field in the driver. Fixes: 2958d17a8984 ("octeontx2-pf: Add support for ptp 1-step mode on CN10K silicon") Signed-off-by: Geetha sowjanya Signed-off-by: Hariprasad Kelam Signed-off-by: Sunil Kovvuri Goutham Signed-off-by: Sai Krishna Link: https://lore.kernel.org/r/20230222113600.1965116-1-saikrishnag@marvell.com Signed-off-by: Paolo Abeni Signed-off-by: Sasha Levin --- .../marvell/octeontx2/nic/otx2_txrx.c | 76 ++++++++++++++----- 1 file changed, 57 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c index ef10aef3cda0..7045fedfd73a 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "otx2_reg.h" #include "otx2_common.h" @@ -699,7 +700,7 @@ static void otx2_sqe_add_ext(struct otx2_nic *pfvf, struct otx2_snd_queue *sq, static void otx2_sqe_add_mem(struct otx2_snd_queue *sq, int *offset, int alg, u64 iova, int ptp_offset, - u64 base_ns, int udp_csum) + u64 base_ns, bool udp_csum_crt) { struct nix_sqe_mem_s *mem; @@ -711,7 +712,7 @@ static void otx2_sqe_add_mem(struct otx2_snd_queue *sq, int *offset, if (ptp_offset) { mem->start_offset = ptp_offset; - mem->udp_csum_crt = udp_csum; + mem->udp_csum_crt = !!udp_csum_crt; mem->base_ns = base_ns; mem->step_type = 1; } @@ -986,10 +987,11 @@ static bool otx2_validate_network_transport(struct sk_buff *skb) return false; } -static bool otx2_ptp_is_sync(struct sk_buff *skb, int *offset, int *udp_csum) +static bool otx2_ptp_is_sync(struct sk_buff *skb, int *offset, bool *udp_csum_crt) { struct ethhdr *eth = (struct ethhdr *)(skb->data); u16 nix_offload_hlen = 0, inner_vhlen = 0; + bool udp_hdr_present = false, is_sync; u8 *data = skb->data, *msgtype; __be16 proto = eth->h_proto; int network_depth = 0; @@ -1029,45 +1031,81 @@ static bool otx2_ptp_is_sync(struct sk_buff *skb, int *offset, int *udp_csum) if (!otx2_validate_network_transport(skb)) return false; - *udp_csum = 1; *offset = nix_offload_hlen + skb_transport_offset(skb) + sizeof(struct udphdr); + udp_hdr_present = true; + } msgtype = data + *offset; - /* Check PTP messageId is SYNC or not */ - return (*msgtype & 0xf) == 0; + is_sync = !(*msgtype & 0xf); + if (is_sync) + *udp_csum_crt = udp_hdr_present; + else + *offset = 0; + + return is_sync; } static void otx2_set_txtstamp(struct otx2_nic *pfvf, struct sk_buff *skb, struct otx2_snd_queue *sq, int *offset) { + struct ethhdr *eth = (struct ethhdr *)(skb->data); struct ptpv2_tstamp *origin_tstamp; - int ptp_offset = 0, udp_csum = 0; + bool udp_csum_crt = false; + unsigned int udphoff; struct timespec64 ts; + int ptp_offset = 0; + __wsum skb_csum; u64 iova; if (unlikely(!skb_shinfo(skb)->gso_size && (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))) { - if (unlikely(pfvf->flags & OTX2_FLAG_PTP_ONESTEP_SYNC)) { - if (otx2_ptp_is_sync(skb, &ptp_offset, &udp_csum)) { - origin_tstamp = (struct ptpv2_tstamp *) - ((u8 *)skb->data + ptp_offset + - PTP_SYNC_SEC_OFFSET); - ts = ns_to_timespec64(pfvf->ptp->tstamp); - origin_tstamp->seconds_msb = htons((ts.tv_sec >> 32) & 0xffff); - origin_tstamp->seconds_lsb = htonl(ts.tv_sec & 0xffffffff); - origin_tstamp->nanoseconds = htonl(ts.tv_nsec); - /* Point to correction field in PTP packet */ - ptp_offset += 8; + if (unlikely(pfvf->flags & OTX2_FLAG_PTP_ONESTEP_SYNC && + otx2_ptp_is_sync(skb, &ptp_offset, &udp_csum_crt))) { + origin_tstamp = (struct ptpv2_tstamp *) + ((u8 *)skb->data + ptp_offset + + PTP_SYNC_SEC_OFFSET); + ts = ns_to_timespec64(pfvf->ptp->tstamp); + origin_tstamp->seconds_msb = htons((ts.tv_sec >> 32) & 0xffff); + origin_tstamp->seconds_lsb = htonl(ts.tv_sec & 0xffffffff); + origin_tstamp->nanoseconds = htonl(ts.tv_nsec); + /* Point to correction field in PTP packet */ + ptp_offset += 8; + + /* When user disables hw checksum, stack calculates the csum, + * but it does not cover ptp timestamp which is added later. + * Recalculate the checksum manually considering the timestamp. + */ + if (udp_csum_crt) { + struct udphdr *uh = udp_hdr(skb); + + if (skb->ip_summed != CHECKSUM_PARTIAL && uh->check != 0) { + udphoff = skb_transport_offset(skb); + uh->check = 0; + skb_csum = skb_checksum(skb, udphoff, skb->len - udphoff, + 0); + if (ntohs(eth->h_proto) == ETH_P_IPV6) + uh->check = csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, + skb->len - udphoff, + ipv6_hdr(skb)->nexthdr, + skb_csum); + else + uh->check = csum_tcpudp_magic(ip_hdr(skb)->saddr, + ip_hdr(skb)->daddr, + skb->len - udphoff, + IPPROTO_UDP, + skb_csum); + } } } else { skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; } iova = sq->timestamps->iova + (sq->head * sizeof(u64)); otx2_sqe_add_mem(sq, offset, NIX_SENDMEMALG_E_SETTSTMP, iova, - ptp_offset, pfvf->ptp->base_ns, udp_csum); + ptp_offset, pfvf->ptp->base_ns, udp_csum_crt); } else { skb_tx_timestamp(skb); } From d28467230dd9b9d560e1003a5c5c58d3ddf457c0 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Wed, 22 Feb 2023 15:42:41 -0500 Subject: [PATCH 071/201] net: sunhme: Fix region request [ Upstream commit ee0a735fd97ccde766ab557d1fc722c92cebacda ] devm_request_region is for I/O regions. Use devm_request_mem_region instead. This fixes the driver failing to probe since 99df45c9e0a4 ("sunhme: fix an IS_ERR() vs NULL check in probe"), which checked the result. Fixes: 914d9b2711dd ("sunhme: switch to devres") Signed-off-by: Sean Anderson Reviewed-by: Pavan Chebbi Link: https://lore.kernel.org/r/20230222204242.2658247-1-seanga2@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/sun/sunhme.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c index 1c16548415cd..b0c7ab74a82e 100644 --- a/drivers/net/ethernet/sun/sunhme.c +++ b/drivers/net/ethernet/sun/sunhme.c @@ -2894,8 +2894,10 @@ static int happy_meal_pci_probe(struct pci_dev *pdev, goto err_out_clear_quattro; } - hpreg_res = devm_request_region(&pdev->dev, pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0), DRV_NAME); + hpreg_res = devm_request_mem_region(&pdev->dev, + pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0), + DRV_NAME); if (!hpreg_res) { err = -EBUSY; dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n"); From 03c3a5584a0a29821e59b7834635ce823050caaa Mon Sep 17 00:00:00 2001 From: Xin Long Date: Wed, 22 Feb 2023 12:07:21 -0500 Subject: [PATCH 072/201] sctp: add a refcnt in sctp_stream_priorities to avoid a nested loop [ Upstream commit 68ba44639537de6f91fe32783766322d41848127 ] With this refcnt added in sctp_stream_priorities, we don't need to traverse all streams to check if the prio is used by other streams when freeing one stream's prio in sctp_sched_prio_free_sid(). This can avoid a nested loop (up to 65535 * 65535), which may cause a stuck as Ying reported: watchdog: BUG: soft lockup - CPU#23 stuck for 26s! [ksoftirqd/23:136] Call Trace: sctp_sched_prio_free_sid+0xab/0x100 [sctp] sctp_stream_free_ext+0x64/0xa0 [sctp] sctp_stream_free+0x31/0x50 [sctp] sctp_association_free+0xa5/0x200 [sctp] Note that it doesn't need to use refcount_t type for this counter, as its accessing is always protected under the sock lock. v1->v2: - add a check in sctp_sched_prio_set to avoid the possible prio_head refcnt overflow. Fixes: 9ed7bfc79542 ("sctp: fix memory leak in sctp_stream_outq_migrate()") Reported-by: Ying Xu Acked-by: Marcelo Ricardo Leitner Signed-off-by: Xin Long Link: https://lore.kernel.org/r/825eb0c905cb864991eba335f4a2b780e543f06b.1677085641.git.lucien.xin@gmail.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- include/net/sctp/structs.h | 1 + net/sctp/stream_sched_prio.c | 52 +++++++++++++++--------------------- 2 files changed, 22 insertions(+), 31 deletions(-) diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 350f250b0dc7..00ee9eb601a6 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1409,6 +1409,7 @@ struct sctp_stream_priorities { /* The next stream in line */ struct sctp_stream_out_ext *next; __u16 prio; + __u16 users; }; struct sctp_stream_out_ext { diff --git a/net/sctp/stream_sched_prio.c b/net/sctp/stream_sched_prio.c index 4fc9f2923ed1..7dd9f8b387cc 100644 --- a/net/sctp/stream_sched_prio.c +++ b/net/sctp/stream_sched_prio.c @@ -25,6 +25,18 @@ static void sctp_sched_prio_unsched_all(struct sctp_stream *stream); +static struct sctp_stream_priorities *sctp_sched_prio_head_get(struct sctp_stream_priorities *p) +{ + p->users++; + return p; +} + +static void sctp_sched_prio_head_put(struct sctp_stream_priorities *p) +{ + if (p && --p->users == 0) + kfree(p); +} + static struct sctp_stream_priorities *sctp_sched_prio_new_head( struct sctp_stream *stream, int prio, gfp_t gfp) { @@ -38,6 +50,7 @@ static struct sctp_stream_priorities *sctp_sched_prio_new_head( INIT_LIST_HEAD(&p->active); p->next = NULL; p->prio = prio; + p->users = 1; return p; } @@ -53,7 +66,7 @@ static struct sctp_stream_priorities *sctp_sched_prio_get_head( */ list_for_each_entry(p, &stream->prio_list, prio_sched) { if (p->prio == prio) - return p; + return sctp_sched_prio_head_get(p); if (p->prio > prio) break; } @@ -70,7 +83,7 @@ static struct sctp_stream_priorities *sctp_sched_prio_get_head( */ break; if (p->prio == prio) - return p; + return sctp_sched_prio_head_get(p); } /* If not even there, allocate a new one. */ @@ -154,32 +167,21 @@ static int sctp_sched_prio_set(struct sctp_stream *stream, __u16 sid, struct sctp_stream_out_ext *soute = sout->ext; struct sctp_stream_priorities *prio_head, *old; bool reschedule = false; - int i; + + old = soute->prio_head; + if (old && old->prio == prio) + return 0; prio_head = sctp_sched_prio_get_head(stream, prio, gfp); if (!prio_head) return -ENOMEM; reschedule = sctp_sched_prio_unsched(soute); - old = soute->prio_head; soute->prio_head = prio_head; if (reschedule) sctp_sched_prio_sched(stream, soute); - if (!old) - /* Happens when we set the priority for the first time */ - return 0; - - for (i = 0; i < stream->outcnt; i++) { - soute = SCTP_SO(stream, i)->ext; - if (soute && soute->prio_head == old) - /* It's still in use, nothing else to do here. */ - return 0; - } - - /* No hits, we are good to free it. */ - kfree(old); - + sctp_sched_prio_head_put(old); return 0; } @@ -206,20 +208,8 @@ static int sctp_sched_prio_init_sid(struct sctp_stream *stream, __u16 sid, static void sctp_sched_prio_free_sid(struct sctp_stream *stream, __u16 sid) { - struct sctp_stream_priorities *prio = SCTP_SO(stream, sid)->ext->prio_head; - int i; - - if (!prio) - return; - + sctp_sched_prio_head_put(SCTP_SO(stream, sid)->ext->prio_head); SCTP_SO(stream, sid)->ext->prio_head = NULL; - for (i = 0; i < stream->outcnt; i++) { - if (SCTP_SO(stream, i)->ext && - SCTP_SO(stream, i)->ext->prio_head == prio) - return; - } - - kfree(prio); } static void sctp_sched_prio_free(struct sctp_stream *stream) From 8dba9e7073a06cbf8bd70f4ab764a41328d22641 Mon Sep 17 00:00:00 2001 From: Deepak R Varma Date: Wed, 22 Feb 2023 18:58:48 +0530 Subject: [PATCH 073/201] octeontx2-pf: Use correct struct reference in test condition [ Upstream commit 3acd9db9293f3b33ac04e8d44ed05b604ad1ac26 ] Fix the typo/copy-paste error by replacing struct variable ah_esp_mask name by ah_esp_hdr. Issue identified using doublebitand.cocci Coccinelle semantic patch. Fixes: b7cf966126eb ("octeontx2-pf: Add flow classification using IP next level protocol") Link: https://lore.kernel.org/all/20210111112537.3277-1-naveenm@marvell.com/ Signed-off-by: Deepak R Varma Link: https://lore.kernel.org/r/Y/YYkKddeHOt80cO@ubun2204.myguest.virtualbox.org Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c index 709fc0114fbd..0f7345a96965 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c @@ -765,7 +765,7 @@ static int otx2_prepare_ipv6_flow(struct ethtool_rx_flow_spec *fsp, /* NPC profile doesn't extract AH/ESP header fields */ if ((ah_esp_mask->spi & ah_esp_hdr->spi) || - (ah_esp_mask->tclass & ah_esp_mask->tclass)) + (ah_esp_mask->tclass & ah_esp_hdr->tclass)) return -EOPNOTSUPP; if (flow_type == AH_V6_FLOW) From 896f014a17614070d1ae41dcb268cc1e4a3d6f05 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 23 Feb 2023 08:38:45 +0000 Subject: [PATCH 074/201] net: fix __dev_kfree_skb_any() vs drop monitor [ Upstream commit ac3ad19584b26fae9ac86e4faebe790becc74491 ] dev_kfree_skb() is aliased to consume_skb(). When a driver is dropping a packet by calling dev_kfree_skb_any() we should propagate the drop reason instead of pretending the packet was consumed. Note: Now we have enum skb_drop_reason we could remove enum skb_free_reason (for linux-6.4) v2: added an unlikely(), suggested by Yunsheng Lin. Fixes: e6247027e517 ("net: introduce dev_consume_skb_any()") Signed-off-by: Eric Dumazet Cc: Yunsheng Lin Reviewed-by: Yunsheng Lin Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/core/dev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index 7a2a4650a898..24eae99dfe05 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3146,8 +3146,10 @@ void __dev_kfree_skb_any(struct sk_buff *skb, enum skb_free_reason reason) { if (in_hardirq() || irqs_disabled()) __dev_kfree_skb_irq(skb, reason); + else if (unlikely(reason == SKB_REASON_DROPPED)) + kfree_skb(skb); else - dev_kfree_skb(skb); + consume_skb(skb); } EXPORT_SYMBOL(__dev_kfree_skb_any); From db886cb3ecc6396127799751ce879483404a4bb4 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Mon, 30 Jan 2023 12:30:35 +0100 Subject: [PATCH 075/201] 9p/xen: fix version parsing [ Upstream commit f1956f4ec15195ec60976d9b5625326285ab102e ] When connecting the Xen 9pfs frontend to the backend, the "versions" Xenstore entry written by the backend is parsed in a wrong way. The "versions" entry is defined to contain the versions supported by the backend separated by commas (e.g. "1,2"). Today only version "1" is defined. Unfortunately the frontend doesn't look for "1" being listed in the entry, but it is expecting the entry to have the value "1". This will result in failure as soon as the backend will support e.g. versions "1" and "2". Fix that by scanning the entry correctly. Link: https://lkml.kernel.org/r/20230130113036.7087-2-jgross@suse.com Fixes: 71ebd71921e4 ("xen/9pfs: connect to the backend") Signed-off-by: Juergen Gross Reviewed-by: Simon Horman Signed-off-by: Dominique Martinet Signed-off-by: Eric Van Hensbergen Signed-off-by: Sasha Levin --- net/9p/trans_xen.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/net/9p/trans_xen.c b/net/9p/trans_xen.c index cf1b89ba522b..80cc0289dd0d 100644 --- a/net/9p/trans_xen.c +++ b/net/9p/trans_xen.c @@ -377,13 +377,19 @@ static int xen_9pfs_front_probe(struct xenbus_device *dev, int ret, i; struct xenbus_transaction xbt; struct xen_9pfs_front_priv *priv = NULL; - char *versions; + char *versions, *v; unsigned int max_rings, max_ring_order, len = 0; versions = xenbus_read(XBT_NIL, dev->otherend, "versions", &len); if (IS_ERR(versions)) return PTR_ERR(versions); - if (strcmp(versions, "1")) { + for (v = versions; *v; v++) { + if (simple_strtoul(v, &v, 10) == 1) { + v = NULL; + break; + } + } + if (v) { kfree(versions); return -EINVAL; } From 4f0e9244770f5b75a16d8c0929063cd336926764 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Mon, 30 Jan 2023 12:30:36 +0100 Subject: [PATCH 076/201] 9p/xen: fix connection sequence [ Upstream commit c15fe55d14b3b4ded5af2a3260877460a6ffb8ad ] Today the connection sequence of the Xen 9pfs frontend doesn't match the documented sequence. It can work reliably only for a PV 9pfs device having been added at boot time already, as the frontend is not waiting for the backend to have set its state to "XenbusStateInitWait" before reading the backend properties from Xenstore. Fix that by following the documented sequence [1] (the documentation has a bug, so the reference is for the patch fixing that). [1]: https://lore.kernel.org/xen-devel/20230130090937.31623-1-jgross@suse.com/T/#u Link: https://lkml.kernel.org/r/20230130113036.7087-3-jgross@suse.com Fixes: 868eb122739a ("xen/9pfs: introduce Xen 9pfs transport driver") Signed-off-by: Juergen Gross Reviewed-by: Simon Horman Signed-off-by: Dominique Martinet Signed-off-by: Eric Van Hensbergen Signed-off-by: Sasha Levin --- net/9p/trans_xen.c | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/net/9p/trans_xen.c b/net/9p/trans_xen.c index 80cc0289dd0d..75c03a82baf3 100644 --- a/net/9p/trans_xen.c +++ b/net/9p/trans_xen.c @@ -371,12 +371,11 @@ out: return ret; } -static int xen_9pfs_front_probe(struct xenbus_device *dev, - const struct xenbus_device_id *id) +static int xen_9pfs_front_init(struct xenbus_device *dev) { int ret, i; struct xenbus_transaction xbt; - struct xen_9pfs_front_priv *priv = NULL; + struct xen_9pfs_front_priv *priv = dev_get_drvdata(&dev->dev); char *versions, *v; unsigned int max_rings, max_ring_order, len = 0; @@ -404,11 +403,6 @@ static int xen_9pfs_front_probe(struct xenbus_device *dev, if (p9_xen_trans.maxsize > XEN_FLEX_RING_SIZE(max_ring_order)) p9_xen_trans.maxsize = XEN_FLEX_RING_SIZE(max_ring_order) / 2; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->dev = dev; priv->num_rings = XEN_9PFS_NUM_RINGS; priv->rings = kcalloc(priv->num_rings, sizeof(*priv->rings), GFP_KERNEL); @@ -467,23 +461,35 @@ static int xen_9pfs_front_probe(struct xenbus_device *dev, goto error; } - write_lock(&xen_9pfs_lock); - list_add_tail(&priv->list, &xen_9pfs_devs); - write_unlock(&xen_9pfs_lock); - dev_set_drvdata(&dev->dev, priv); - xenbus_switch_state(dev, XenbusStateInitialised); - return 0; error_xenbus: xenbus_transaction_end(xbt, 1); xenbus_dev_fatal(dev, ret, "writing xenstore"); error: - dev_set_drvdata(&dev->dev, NULL); xen_9pfs_front_free(priv); return ret; } +static int xen_9pfs_front_probe(struct xenbus_device *dev, + const struct xenbus_device_id *id) +{ + struct xen_9pfs_front_priv *priv = NULL; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + dev_set_drvdata(&dev->dev, priv); + + write_lock(&xen_9pfs_lock); + list_add_tail(&priv->list, &xen_9pfs_devs); + write_unlock(&xen_9pfs_lock); + + return 0; +} + static int xen_9pfs_front_resume(struct xenbus_device *dev) { dev_warn(&dev->dev, "suspend/resume unsupported\n"); @@ -502,6 +508,8 @@ static void xen_9pfs_front_changed(struct xenbus_device *dev, break; case XenbusStateInitWait: + if (!xen_9pfs_front_init(dev)) + xenbus_switch_state(dev, XenbusStateInitialised); break; case XenbusStateConnected: From 7dd49d434d2e2223969ff4deeaa4ec8da45d6fcc Mon Sep 17 00:00:00 2001 From: Zhengchao Shao Date: Wed, 4 Jan 2023 10:04:24 +0800 Subject: [PATCH 077/201] 9p/rdma: unmap receive dma buffer in rdma_request()/post_recv() [ Upstream commit 74a25e6e916cb57dab4267a96fbe8864ed21abdb ] When down_interruptible() or ib_post_send() failed in rdma_request(), receive dma buffer is not unmapped. Add unmap action to error path. Also if ib_post_recv() failed in post_recv(), dma buffer is not unmapped. Add unmap action to error path. Link: https://lkml.kernel.org/r/20230104020424.611926-1-shaozhengchao@huawei.com Fixes: fc79d4b104f0 ("9p: rdma: RDMA Transport Support for 9P") Signed-off-by: Zhengchao Shao Reviewed-by: Leon Romanovsky Signed-off-by: Dominique Martinet Signed-off-by: Eric Van Hensbergen Signed-off-by: Sasha Levin --- net/9p/trans_rdma.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c index e9a830c69058..29a9292303ea 100644 --- a/net/9p/trans_rdma.c +++ b/net/9p/trans_rdma.c @@ -386,6 +386,7 @@ post_recv(struct p9_client *client, struct p9_rdma_context *c) struct p9_trans_rdma *rdma = client->trans; struct ib_recv_wr wr; struct ib_sge sge; + int ret; c->busa = ib_dma_map_single(rdma->cm_id->device, c->rc.sdata, client->msize, @@ -403,7 +404,12 @@ post_recv(struct p9_client *client, struct p9_rdma_context *c) wr.wr_cqe = &c->cqe; wr.sg_list = &sge; wr.num_sge = 1; - return ib_post_recv(rdma->qp, &wr, NULL); + + ret = ib_post_recv(rdma->qp, &wr, NULL); + if (ret) + ib_dma_unmap_single(rdma->cm_id->device, c->busa, + client->msize, DMA_FROM_DEVICE); + return ret; error: p9_debug(P9_DEBUG_ERROR, "EIO\n"); @@ -500,7 +506,7 @@ dont_need_post_recv: if (down_interruptible(&rdma->sq_sem)) { err = -EINTR; - goto send_error; + goto dma_unmap; } /* Mark request as `sent' *before* we actually send it, @@ -510,11 +516,14 @@ dont_need_post_recv: WRITE_ONCE(req->status, REQ_STATUS_SENT); err = ib_post_send(rdma->qp, &wr, NULL); if (err) - goto send_error; + goto dma_unmap; /* Success */ return 0; +dma_unmap: + ib_dma_unmap_single(rdma->cm_id->device, c->busa, + c->req->tc.size, DMA_TO_DEVICE); /* Handle errors that happened during or while preparing the send: */ send_error: WRITE_ONCE(req->status, REQ_STATUS_ERROR); From f6c0536b41e6e35ff81dfaa1fa83f2c8f49216bd Mon Sep 17 00:00:00 2001 From: Krishna Yarlagadda Date: Fri, 24 Feb 2023 22:10:34 +0530 Subject: [PATCH 078/201] spi: tegra210-quad: Fix validate combined sequence [ Upstream commit 047ee71ae4f412d8819e39e4b08c588fa299cfc2 ] Check for non dma transfers that do not fit in FIFO has issue and skips combined sequence for Tegra234 & Tegra241 which does not have GPCDMA. Fixes: 1b8342cc4a38 ("spi: tegra210-quad: combined sequence mode") Signed-off-by: Krishna Yarlagadda Link: https://lore.kernel.org/r/20230224164034.56933-1-kyarlagadda@nvidia.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spi-tegra210-quad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c index 9f356612ba7e..6498948e150a 100644 --- a/drivers/spi/spi-tegra210-quad.c +++ b/drivers/spi/spi-tegra210-quad.c @@ -1297,7 +1297,7 @@ static bool tegra_qspi_validate_cmb_seq(struct tegra_qspi *tqspi, if (xfer->len > 4 || xfer->len < 3) return false; xfer = list_next_entry(xfer, transfer_list); - if (!tqspi->soc_data->has_dma || xfer->len > (QSPI_FIFO_DEPTH << 2)) + if (!tqspi->soc_data->has_dma && xfer->len > (QSPI_FIFO_DEPTH << 2)) return false; return true; From 234cffda95e1049f58e8ec136ef105c633f0ed19 Mon Sep 17 00:00:00 2001 From: Vadim Fedorenko Date: Thu, 2 Feb 2023 09:13:54 -0800 Subject: [PATCH 079/201] mlx5: fix skb leak while fifo resync and push [ Upstream commit e435941b1da1a0be4ff8a7ae425774c76a5ac514 ] During ptp resync operation SKBs were poped from the fifo but were never freed neither by napi_consume nor by dev_kfree_skb_any. Add call to napi_consume_skb to properly free SKBs. Another leak was happening because mlx5e_skb_fifo_has_room() had an error in the check. Comparing free running counters works well unless C promotes the types to something wider than the counter. In this case counters are u16 but the result of the substraction is promouted to int and it causes wrong result (negative value) of the check when producer have already overlapped but consumer haven't yet. Explicit cast to u16 fixes the issue. Fixes: 58a518948f60 ("net/mlx5e: Add resiliency for PTP TX port timestamp") Reviewed-by: Gal Pressman Reviewed-by: Tariq Toukan Signed-off-by: Vadim Fedorenko Signed-off-by: Saeed Mahameed Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c | 6 ++++-- drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c index 8469e9c38670..b72de2b520ec 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c @@ -86,7 +86,8 @@ static bool mlx5e_ptp_ts_cqe_drop(struct mlx5e_ptpsq *ptpsq, u16 skb_cc, u16 skb return (ptpsq->ts_cqe_ctr_mask && (skb_cc != skb_id)); } -static void mlx5e_ptp_skb_fifo_ts_cqe_resync(struct mlx5e_ptpsq *ptpsq, u16 skb_cc, u16 skb_id) +static void mlx5e_ptp_skb_fifo_ts_cqe_resync(struct mlx5e_ptpsq *ptpsq, u16 skb_cc, + u16 skb_id, int budget) { struct skb_shared_hwtstamps hwts = {}; struct sk_buff *skb; @@ -98,6 +99,7 @@ static void mlx5e_ptp_skb_fifo_ts_cqe_resync(struct mlx5e_ptpsq *ptpsq, u16 skb_ hwts.hwtstamp = mlx5e_skb_cb_get_hwts(skb)->cqe_hwtstamp; skb_tstamp_tx(skb, &hwts); ptpsq->cq_stats->resync_cqe++; + napi_consume_skb(skb, budget); skb_cc = PTP_WQE_CTR2IDX(ptpsq->skb_fifo_cc); } } @@ -119,7 +121,7 @@ static void mlx5e_ptp_handle_ts_cqe(struct mlx5e_ptpsq *ptpsq, } if (mlx5e_ptp_ts_cqe_drop(ptpsq, skb_cc, skb_id)) - mlx5e_ptp_skb_fifo_ts_cqe_resync(ptpsq, skb_cc, skb_id); + mlx5e_ptp_skb_fifo_ts_cqe_resync(ptpsq, skb_cc, skb_id, budget); skb = mlx5e_skb_fifo_pop(&ptpsq->skb_fifo); hwtstamp = mlx5e_cqe_ts_to_ns(sq->ptp_cyc2time, sq->clock, get_cqe_ts(cqe)); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h index 853f312cd757..15a5a57b47b8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h @@ -81,7 +81,7 @@ void mlx5e_free_txqsq_descs(struct mlx5e_txqsq *sq); static inline bool mlx5e_skb_fifo_has_room(struct mlx5e_skb_fifo *fifo) { - return (*fifo->pc - *fifo->cc) < fifo->mask; + return (u16)(*fifo->pc - *fifo->cc) < fifo->mask; } static inline bool From 52e6e7a0bc04c85012a9251c7cf2d444a77eb966 Mon Sep 17 00:00:00 2001 From: Vadim Fedorenko Date: Thu, 2 Feb 2023 09:13:55 -0800 Subject: [PATCH 080/201] mlx5: fix possible ptp queue fifo use-after-free [ Upstream commit 3a50cf1e8e5157b82268eee7e330dbe5736a0948 ] Fifo indexes are not checked during pop operations and it leads to potential use-after-free when poping from empty queue. Such case was possible during re-sync action. WARN_ON_ONCE covers future cases. There were out-of-order cqe spotted which lead to drain of the queue and use-after-free because of lack of fifo pointers check. Special check and counter are added to avoid resync operation if SKB could not exist in the fifo because of OOO cqe (skb_id must be between consumer and producer index). Fixes: 58a518948f60 ("net/mlx5e: Add resiliency for PTP TX port timestamp") Signed-off-by: Vadim Fedorenko Signed-off-by: Saeed Mahameed Signed-off-by: Sasha Levin --- .../net/ethernet/mellanox/mlx5/core/en/ptp.c | 19 ++++++++++++++++++- .../net/ethernet/mellanox/mlx5/core/en/txrx.h | 2 ++ .../ethernet/mellanox/mlx5/core/en_stats.c | 1 + .../ethernet/mellanox/mlx5/core/en_stats.h | 1 + 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c index b72de2b520ec..ae75e230170b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c @@ -86,6 +86,17 @@ static bool mlx5e_ptp_ts_cqe_drop(struct mlx5e_ptpsq *ptpsq, u16 skb_cc, u16 skb return (ptpsq->ts_cqe_ctr_mask && (skb_cc != skb_id)); } +static bool mlx5e_ptp_ts_cqe_ooo(struct mlx5e_ptpsq *ptpsq, u16 skb_id) +{ + u16 skb_cc = PTP_WQE_CTR2IDX(ptpsq->skb_fifo_cc); + u16 skb_pc = PTP_WQE_CTR2IDX(ptpsq->skb_fifo_pc); + + if (PTP_WQE_CTR2IDX(skb_id - skb_cc) >= PTP_WQE_CTR2IDX(skb_pc - skb_cc)) + return true; + + return false; +} + static void mlx5e_ptp_skb_fifo_ts_cqe_resync(struct mlx5e_ptpsq *ptpsq, u16 skb_cc, u16 skb_id, int budget) { @@ -120,8 +131,14 @@ static void mlx5e_ptp_handle_ts_cqe(struct mlx5e_ptpsq *ptpsq, goto out; } - if (mlx5e_ptp_ts_cqe_drop(ptpsq, skb_cc, skb_id)) + if (mlx5e_ptp_ts_cqe_drop(ptpsq, skb_cc, skb_id)) { + if (mlx5e_ptp_ts_cqe_ooo(ptpsq, skb_id)) { + /* already handled by a previous resync */ + ptpsq->cq_stats->ooo_cqe_drop++; + return; + } mlx5e_ptp_skb_fifo_ts_cqe_resync(ptpsq, skb_cc, skb_id, budget); + } skb = mlx5e_skb_fifo_pop(&ptpsq->skb_fifo); hwtstamp = mlx5e_cqe_ts_to_ns(sq->ptp_cyc2time, sq->clock, get_cqe_ts(cqe)); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h index 15a5a57b47b8..1b3a65325ece 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h @@ -297,6 +297,8 @@ void mlx5e_skb_fifo_push(struct mlx5e_skb_fifo *fifo, struct sk_buff *skb) static inline struct sk_buff *mlx5e_skb_fifo_pop(struct mlx5e_skb_fifo *fifo) { + WARN_ON_ONCE(*fifo->pc == *fifo->cc); + return *mlx5e_skb_fifo_get(fifo, (*fifo->cc)++); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c index 03c1841970f1..f7f54550a8bb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c @@ -2121,6 +2121,7 @@ static const struct counter_desc ptp_cq_stats_desc[] = { { MLX5E_DECLARE_PTP_CQ_STAT(struct mlx5e_ptp_cq_stats, abort_abs_diff_ns) }, { MLX5E_DECLARE_PTP_CQ_STAT(struct mlx5e_ptp_cq_stats, resync_cqe) }, { MLX5E_DECLARE_PTP_CQ_STAT(struct mlx5e_ptp_cq_stats, resync_event) }, + { MLX5E_DECLARE_PTP_CQ_STAT(struct mlx5e_ptp_cq_stats, ooo_cqe_drop) }, }; static const struct counter_desc ptp_rq_stats_desc[] = { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h index 9f781085be47..52a67efafcd3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h @@ -459,6 +459,7 @@ struct mlx5e_ptp_cq_stats { u64 abort_abs_diff_ns; u64 resync_cqe; u64 resync_event; + u64 ooo_cqe_drop; }; struct mlx5e_stats { From 2a0b214ab49f36460adcae02bed2d13858a7f3b2 Mon Sep 17 00:00:00 2001 From: Maher Sanalla Date: Wed, 15 Feb 2023 20:12:05 +0200 Subject: [PATCH 081/201] net/mlx5: ECPF, wait for VF pages only after disabling host PFs [ Upstream commit e1ed30c8c09abc85a01c897845bdbd08c0333353 ] Currently, during the early stages of their unloading, particularly during SRIOV disablement, PFs/ECPFs wait on the release of all of their VFs memory pages. Furthermore, ECPFs are considered the page supplier for host VFs, hence the host VFs memory pages are freed only during ECPF cleanup when host interfaces get disabled. Thus, disabling SRIOV early in unload timeline causes the DPU ECPF to stall on driver unload while waiting on the release of host VF pages that won't be freed before host interfaces get disabled later on. Therefore, for ECPFs, wait on the release of VFs pages only after the disablement of host PFs during ECPF cleanup flow. Then, host PFs and VFs are disabled and their memory shall be freed accordingly. Fixes: 143a41d7623d ("net/mlx5: Disable SRIOV before PF removal") Signed-off-by: Maher Sanalla Reviewed-by: Moshe Shemesh Signed-off-by: Saeed Mahameed Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlx5/core/ecpf.c | 4 ++++ drivers/net/ethernet/mellanox/mlx5/core/sriov.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c b/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c index cdc87ecae5d3..d000236ddbac 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ecpf.c @@ -90,4 +90,8 @@ void mlx5_ec_cleanup(struct mlx5_core_dev *dev) err = mlx5_wait_for_pages(dev, &dev->priv.page_counters[MLX5_HOST_PF]); if (err) mlx5_core_warn(dev, "Timeout reclaiming external host PF pages err(%d)\n", err); + + err = mlx5_wait_for_pages(dev, &dev->priv.page_counters[MLX5_VF]); + if (err) + mlx5_core_warn(dev, "Timeout reclaiming external host VFs pages err(%d)\n", err); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c index 3008e9ce2bbf..20d7662c10fb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c @@ -147,6 +147,10 @@ mlx5_device_disable_sriov(struct mlx5_core_dev *dev, int num_vfs, bool clear_vf) mlx5_eswitch_disable_sriov(dev->priv.eswitch, clear_vf); + /* For ECPFs, skip waiting for host VF pages until ECPF is destroyed */ + if (mlx5_core_is_ecpf(dev)) + return; + if (mlx5_wait_for_pages(dev, &dev->priv.page_counters[MLX5_VF])) mlx5_core_warn(dev, "timeout reclaiming VFs pages\n"); } From a383f5fcc89156d702ac3db3c3a822b6580be1e4 Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Tue, 31 Jan 2023 12:04:30 +0200 Subject: [PATCH 082/201] net/mlx5e: Verify flow_source cap before using it [ Upstream commit 1bf8b0dae8dde6f02520a5ea34fdaa3b39342e69 ] When adding send to vport rule verify flow_source matching is supported by checking the flow_source cap. Fixes: d04442540372 ("net/mlx5: E-Switch, set flow source for send to uplink rule") Signed-off-by: Roi Dayan Reviewed-by: Maor Dickman Signed-off-by: Saeed Mahameed Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index b4e263e8cfb8..235f6f0a7052 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -1043,7 +1043,8 @@ mlx5_eswitch_add_send_to_vport_rule(struct mlx5_eswitch *on_esw, dest.vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID; flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; - if (rep->vport == MLX5_VPORT_UPLINK) + if (MLX5_CAP_ESW_FLOWTABLE(on_esw->dev, flow_source) && + rep->vport == MLX5_VPORT_UPLINK) spec->flow_context.flow_source = MLX5_FLOW_CONTEXT_FLOW_SOURCE_LOCAL_VPORT; flow_rule = mlx5_add_flow_rules(on_esw->fdb_table.offloads.slow_fdb, From 2b7cf1bcd44798c218fe9f08c82921f3c70a0aa1 Mon Sep 17 00:00:00 2001 From: Maor Dickman Date: Wed, 8 Feb 2023 17:44:06 +0200 Subject: [PATCH 083/201] net/mlx5: Geneve, Fix handling of Geneve object id as error code [ Upstream commit d28a06d7dbedc598a06bd1e53a28125f87ca5d0c ] On success, mlx5_geneve_tlv_option_create returns non negative Geneve object id. In case the object id is positive value the caller functions will handle it as an error (non zero) and will fail to offload the Geneve rule. Fix this by changing caller function ,mlx5_geneve_tlv_option_add, to return 0 in case valid non negative object id was provided. Fixes: 0ccc171ea6a2 ("net/mlx5: Geneve, Manage Geneve TLV options") Signed-off-by: Maor Dickman Reviewed-by: Raed Salem Signed-off-by: Saeed Mahameed Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.c index 23361a9ae4fa..6dc83e871cd7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/geneve.c @@ -105,6 +105,7 @@ int mlx5_geneve_tlv_option_add(struct mlx5_geneve *geneve, struct geneve_opt *op geneve->opt_type = opt->type; geneve->obj_id = res; geneve->refcount++; + res = 0; } unlock: From f19d8f93682a75762575fc56616930c1ab667ffc Mon Sep 17 00:00:00 2001 From: Zhang Yi Date: Sun, 29 Jan 2023 11:49:39 +0800 Subject: [PATCH 084/201] ext4: fix incorrect options show of original mount_opt and extend mount_opt2 [ Upstream commit e3645d72f8865ffe36f9dc811540d40aa3c848d3 ] Current _ext4_show_options() do not distinguish MOPT_2 flag, so it mixed extend sbi->s_mount_opt2 options with sbi->s_mount_opt, it could lead to show incorrect options, e.g. show fc_debug_force if we mount with errors=continue mode and miss it if we set. $ mkfs.ext4 /dev/pmem0 $ mount -o errors=remount-ro /dev/pmem0 /mnt $ cat /proc/fs/ext4/pmem0/options | grep fc_debug_force #empty $ mount -o remount,errors=continue /mnt $ cat /proc/fs/ext4/pmem0/options | grep fc_debug_force fc_debug_force $ mount -o remount,errors=remount-ro,fc_debug_force /mnt $ cat /proc/fs/ext4/pmem0/options | grep fc_debug_force #empty Fixes: 995a3ed67fc8 ("ext4: add fast_commit feature and handling for extended mount options") Signed-off-by: Zhang Yi Reviewed-by: Jan Kara Link: https://lore.kernel.org/r/20230129034939.3702550-1-yi.zhang@huaweicloud.com Signed-off-by: Theodore Ts'o Signed-off-by: Sasha Levin --- fs/ext4/ext4.h | 1 + fs/ext4/super.c | 28 +++++++++++++++++++++------- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 4e739902dc03..a2bc440743ae 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1529,6 +1529,7 @@ struct ext4_sb_info { unsigned int s_mount_opt2; unsigned long s_mount_flags; unsigned int s_def_mount_opt; + unsigned int s_def_mount_opt2; ext4_fsblk_t s_sb_block; atomic64_t s_resv_clusters; kuid_t s_resuid; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 22ddd89c868a..801160099958 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -2894,7 +2894,7 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb, { struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_super_block *es = sbi->s_es; - int def_errors, def_mount_opt = sbi->s_def_mount_opt; + int def_errors; const struct mount_opts *m; char sep = nodefs ? '\n' : ','; @@ -2906,15 +2906,28 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb, for (m = ext4_mount_opts; m->token != Opt_err; m++) { int want_set = m->flags & MOPT_SET; + int opt_2 = m->flags & MOPT_2; + unsigned int mount_opt, def_mount_opt; + if (((m->flags & (MOPT_SET|MOPT_CLEAR)) == 0) || m->flags & MOPT_SKIP) continue; - if (!nodefs && !(m->mount_opt & (sbi->s_mount_opt ^ def_mount_opt))) - continue; /* skip if same as the default */ + + if (opt_2) { + mount_opt = sbi->s_mount_opt2; + def_mount_opt = sbi->s_def_mount_opt2; + } else { + mount_opt = sbi->s_mount_opt; + def_mount_opt = sbi->s_def_mount_opt; + } + /* skip if same as the default */ + if (!nodefs && !(m->mount_opt & (mount_opt ^ def_mount_opt))) + continue; + /* select Opt_noFoo vs Opt_Foo */ if ((want_set && - (sbi->s_mount_opt & m->mount_opt) != m->mount_opt) || - (!want_set && (sbi->s_mount_opt & m->mount_opt))) - continue; /* select Opt_noFoo vs Opt_Foo */ + (mount_opt & m->mount_opt) != m->mount_opt) || + (!want_set && (mount_opt & m->mount_opt))) + continue; SEQ_OPTS_PRINT("%s", token2str(m->token)); } @@ -2942,7 +2955,7 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb, if (nodefs || sbi->s_stripe) SEQ_OPTS_PRINT("stripe=%lu", sbi->s_stripe); if (nodefs || EXT4_MOUNT_DATA_FLAGS & - (sbi->s_mount_opt ^ def_mount_opt)) { + (sbi->s_mount_opt ^ sbi->s_def_mount_opt)) { if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) SEQ_OPTS_PUTS("data=journal"); else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA) @@ -5087,6 +5100,7 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb) goto failed_mount; sbi->s_def_mount_opt = sbi->s_mount_opt; + sbi->s_def_mount_opt2 = sbi->s_mount_opt2; err = ext4_check_opt_consistency(fc, sb); if (err < 0) From b2036a252381949d3b743a3de069324ae3028a57 Mon Sep 17 00:00:00 2001 From: Fedor Pchelkin Date: Sat, 25 Feb 2023 13:56:14 +0300 Subject: [PATCH 085/201] nfc: fix memory leak of se_io context in nfc_genl_se_io [ Upstream commit 25ff6f8a5a3b8dc48e8abda6f013e8cc4b14ffea ] The callback context for sending/receiving APDUs to/from the selected secure element is allocated inside nfc_genl_se_io and supposed to be eventually freed in se_io_cb callback function. However, there are several error paths where the bwi_timer is not charged to call se_io_cb later, and the cb_context is leaked. The patch proposes to free the cb_context explicitly on those error paths. At the moment we can't simply check 'dev->ops->se_io()' return value as it may be negative in both cases: when the timer was charged and was not. Fixes: 5ce3f32b5264 ("NFC: netlink: SE API implementation") Reported-by: syzbot+df64c0a2e8d68e78a4fa@syzkaller.appspotmail.com Signed-off-by: Fedor Pchelkin Signed-off-by: Alexey Khoroshilov Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/nfc/st-nci/se.c | 6 ++++++ drivers/nfc/st21nfca/se.c | 6 ++++++ net/nfc/netlink.c | 4 ++++ 3 files changed, 16 insertions(+) diff --git a/drivers/nfc/st-nci/se.c b/drivers/nfc/st-nci/se.c index ec87dd21e054..b2f1ced8e6dd 100644 --- a/drivers/nfc/st-nci/se.c +++ b/drivers/nfc/st-nci/se.c @@ -672,6 +672,12 @@ int st_nci_se_io(struct nci_dev *ndev, u32 se_idx, ST_NCI_EVT_TRANSMIT_DATA, apdu, apdu_length); default: + /* Need to free cb_context here as at the moment we can't + * clearly indicate to the caller if the callback function + * would be called (and free it) or not. In both cases a + * negative value may be returned to the caller. + */ + kfree(cb_context); return -ENODEV; } } diff --git a/drivers/nfc/st21nfca/se.c b/drivers/nfc/st21nfca/se.c index df8d27cf2956..dae288bebcb5 100644 --- a/drivers/nfc/st21nfca/se.c +++ b/drivers/nfc/st21nfca/se.c @@ -236,6 +236,12 @@ int st21nfca_hci_se_io(struct nfc_hci_dev *hdev, u32 se_idx, ST21NFCA_EVT_TRANSMIT_DATA, apdu, apdu_length); default: + /* Need to free cb_context here as at the moment we can't + * clearly indicate to the caller if the callback function + * would be called (and free it) or not. In both cases a + * negative value may be returned to the caller. + */ + kfree(cb_context); return -ENODEV; } } diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index 1fc339084d89..348bf561bc9f 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -1442,7 +1442,11 @@ static int nfc_se_io(struct nfc_dev *dev, u32 se_idx, rc = dev->ops->se_io(dev, se_idx, apdu, apdu_length, cb, cb_context); + device_unlock(&dev->dev); + return rc; + error: + kfree(cb_context); device_unlock(&dev->dev); return rc; } From d3ad82430e9bda65efff84622255099e14447275 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Tue, 31 Jan 2023 16:05:11 -0300 Subject: [PATCH 086/201] net/sched: transition act_pedit to rcu and percpu stats [ Upstream commit 52cf89f78c01bf39973f3e70d366921d70faff7a ] The software pedit action didn't get the same love as some of the other actions and it's still using spinlocks and shared stats in the datapath. Transition the action to rcu and percpu stats as this improves the action's performance dramatically on multiple cpu deployments. Reviewed-by: Jamal Hadi Salim Signed-off-by: Pedro Tammela Reviewed-by: Simon Horman Signed-off-by: Paolo Abeni Stable-dep-of: e9e42292ea76 ("net/sched: act_pedit: fix action bind logic") Signed-off-by: Sasha Levin --- include/net/tc_act/tc_pedit.h | 81 ++++++++++++++---- net/sched/act_pedit.c | 156 ++++++++++++++++++++-------------- 2 files changed, 157 insertions(+), 80 deletions(-) diff --git a/include/net/tc_act/tc_pedit.h b/include/net/tc_act/tc_pedit.h index 3e02709a1df6..83fe39931781 100644 --- a/include/net/tc_act/tc_pedit.h +++ b/include/net/tc_act/tc_pedit.h @@ -4,22 +4,29 @@ #include #include +#include struct tcf_pedit_key_ex { enum pedit_header_type htype; enum pedit_cmd cmd; }; -struct tcf_pedit { - struct tc_action common; - unsigned char tcfp_nkeys; - unsigned char tcfp_flags; - u32 tcfp_off_max_hint; +struct tcf_pedit_parms { struct tc_pedit_key *tcfp_keys; struct tcf_pedit_key_ex *tcfp_keys_ex; + u32 tcfp_off_max_hint; + unsigned char tcfp_nkeys; + unsigned char tcfp_flags; + struct rcu_head rcu; +}; + +struct tcf_pedit { + struct tc_action common; + struct tcf_pedit_parms __rcu *parms; }; #define to_pedit(a) ((struct tcf_pedit *)a) +#define to_pedit_parms(a) (rcu_dereference(to_pedit(a)->parms)) static inline bool is_tcf_pedit(const struct tc_action *a) { @@ -32,37 +39,81 @@ static inline bool is_tcf_pedit(const struct tc_action *a) static inline int tcf_pedit_nkeys(const struct tc_action *a) { - return to_pedit(a)->tcfp_nkeys; + struct tcf_pedit_parms *parms; + int nkeys; + + rcu_read_lock(); + parms = to_pedit_parms(a); + nkeys = parms->tcfp_nkeys; + rcu_read_unlock(); + + return nkeys; } static inline u32 tcf_pedit_htype(const struct tc_action *a, int index) { - if (to_pedit(a)->tcfp_keys_ex) - return to_pedit(a)->tcfp_keys_ex[index].htype; + u32 htype = TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK; + struct tcf_pedit_parms *parms; - return TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK; + rcu_read_lock(); + parms = to_pedit_parms(a); + if (parms->tcfp_keys_ex) + htype = parms->tcfp_keys_ex[index].htype; + rcu_read_unlock(); + + return htype; } static inline u32 tcf_pedit_cmd(const struct tc_action *a, int index) { - if (to_pedit(a)->tcfp_keys_ex) - return to_pedit(a)->tcfp_keys_ex[index].cmd; + struct tcf_pedit_parms *parms; + u32 cmd = __PEDIT_CMD_MAX; - return __PEDIT_CMD_MAX; + rcu_read_lock(); + parms = to_pedit_parms(a); + if (parms->tcfp_keys_ex) + cmd = parms->tcfp_keys_ex[index].cmd; + rcu_read_unlock(); + + return cmd; } static inline u32 tcf_pedit_mask(const struct tc_action *a, int index) { - return to_pedit(a)->tcfp_keys[index].mask; + struct tcf_pedit_parms *parms; + u32 mask; + + rcu_read_lock(); + parms = to_pedit_parms(a); + mask = parms->tcfp_keys[index].mask; + rcu_read_unlock(); + + return mask; } static inline u32 tcf_pedit_val(const struct tc_action *a, int index) { - return to_pedit(a)->tcfp_keys[index].val; + struct tcf_pedit_parms *parms; + u32 val; + + rcu_read_lock(); + parms = to_pedit_parms(a); + val = parms->tcfp_keys[index].val; + rcu_read_unlock(); + + return val; } static inline u32 tcf_pedit_offset(const struct tc_action *a, int index) { - return to_pedit(a)->tcfp_keys[index].off; + struct tcf_pedit_parms *parms; + u32 off; + + rcu_read_lock(); + parms = to_pedit_parms(a); + off = parms->tcfp_keys[index].off; + rcu_read_unlock(); + + return off; } #endif /* __NET_TC_PED_H */ diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index 94ed5857ce67..655addb31b7f 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -133,6 +133,17 @@ nla_failure: return -EINVAL; } +static void tcf_pedit_cleanup_rcu(struct rcu_head *head) +{ + struct tcf_pedit_parms *parms = + container_of(head, struct tcf_pedit_parms, rcu); + + kfree(parms->tcfp_keys_ex); + kfree(parms->tcfp_keys); + + kfree(parms); +} + static int tcf_pedit_init(struct net *net, struct nlattr *nla, struct nlattr *est, struct tc_action **a, struct tcf_proto *tp, u32 flags, @@ -140,10 +151,9 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, { struct tc_action_net *tn = net_generic(net, act_pedit_ops.net_id); bool bind = flags & TCA_ACT_FLAGS_BIND; - struct nlattr *tb[TCA_PEDIT_MAX + 1]; struct tcf_chain *goto_ch = NULL; - struct tc_pedit_key *keys = NULL; - struct tcf_pedit_key_ex *keys_ex; + struct tcf_pedit_parms *oparms, *nparms; + struct nlattr *tb[TCA_PEDIT_MAX + 1]; struct tc_pedit *parm; struct nlattr *pattr; struct tcf_pedit *p; @@ -180,18 +190,25 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, return -EINVAL; } - keys_ex = tcf_pedit_keys_ex_parse(tb[TCA_PEDIT_KEYS_EX], parm->nkeys); - if (IS_ERR(keys_ex)) - return PTR_ERR(keys_ex); + nparms = kzalloc(sizeof(*nparms), GFP_KERNEL); + if (!nparms) + return -ENOMEM; + + nparms->tcfp_keys_ex = + tcf_pedit_keys_ex_parse(tb[TCA_PEDIT_KEYS_EX], parm->nkeys); + if (IS_ERR(nparms->tcfp_keys_ex)) { + ret = PTR_ERR(nparms->tcfp_keys_ex); + goto out_free; + } index = parm->index; err = tcf_idr_check_alloc(tn, &index, a, bind); if (!err) { - ret = tcf_idr_create(tn, index, est, a, - &act_pedit_ops, bind, false, flags); + ret = tcf_idr_create_from_flags(tn, index, est, a, + &act_pedit_ops, bind, flags); if (ret) { tcf_idr_cleanup(tn, index); - goto out_free; + goto out_free_ex; } ret = ACT_P_CREATED; } else if (err > 0) { @@ -203,7 +220,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, } } else { ret = err; - goto out_free; + goto out_free_ex; } err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); @@ -211,48 +228,50 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, ret = err; goto out_release; } - p = to_pedit(*a); - spin_lock_bh(&p->tcf_lock); - if (ret == ACT_P_CREATED || - (p->tcfp_nkeys && p->tcfp_nkeys != parm->nkeys)) { - keys = kmalloc(ksize, GFP_ATOMIC); - if (!keys) { - spin_unlock_bh(&p->tcf_lock); - ret = -ENOMEM; - goto put_chain; - } - kfree(p->tcfp_keys); - p->tcfp_keys = keys; - p->tcfp_nkeys = parm->nkeys; + nparms->tcfp_off_max_hint = 0; + nparms->tcfp_flags = parm->flags; + nparms->tcfp_nkeys = parm->nkeys; + + nparms->tcfp_keys = kmalloc(ksize, GFP_KERNEL); + if (!nparms->tcfp_keys) { + ret = -ENOMEM; + goto put_chain; } - memcpy(p->tcfp_keys, parm->keys, ksize); - p->tcfp_off_max_hint = 0; - for (i = 0; i < p->tcfp_nkeys; ++i) { - u32 cur = p->tcfp_keys[i].off; + + memcpy(nparms->tcfp_keys, parm->keys, ksize); + + for (i = 0; i < nparms->tcfp_nkeys; ++i) { + u32 cur = nparms->tcfp_keys[i].off; /* sanitize the shift value for any later use */ - p->tcfp_keys[i].shift = min_t(size_t, BITS_PER_TYPE(int) - 1, - p->tcfp_keys[i].shift); + nparms->tcfp_keys[i].shift = min_t(size_t, + BITS_PER_TYPE(int) - 1, + nparms->tcfp_keys[i].shift); /* The AT option can read a single byte, we can bound the actual * value with uchar max. */ - cur += (0xff & p->tcfp_keys[i].offmask) >> p->tcfp_keys[i].shift; + cur += (0xff & nparms->tcfp_keys[i].offmask) >> nparms->tcfp_keys[i].shift; /* Each key touches 4 bytes starting from the computed offset */ - p->tcfp_off_max_hint = max(p->tcfp_off_max_hint, cur + 4); + nparms->tcfp_off_max_hint = + max(nparms->tcfp_off_max_hint, cur + 4); } - p->tcfp_flags = parm->flags; + p = to_pedit(*a); + + spin_lock_bh(&p->tcf_lock); goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); - - kfree(p->tcfp_keys_ex); - p->tcfp_keys_ex = keys_ex; - + oparms = rcu_replace_pointer(p->parms, nparms, 1); spin_unlock_bh(&p->tcf_lock); + + if (oparms) + call_rcu(&oparms->rcu, tcf_pedit_cleanup_rcu); + if (goto_ch) tcf_chain_put_by_act(goto_ch); + return ret; put_chain: @@ -260,19 +279,22 @@ put_chain: tcf_chain_put_by_act(goto_ch); out_release: tcf_idr_release(*a, bind); +out_free_ex: + kfree(nparms->tcfp_keys_ex); out_free: - kfree(keys_ex); + kfree(nparms); return ret; - } static void tcf_pedit_cleanup(struct tc_action *a) { struct tcf_pedit *p = to_pedit(a); - struct tc_pedit_key *keys = p->tcfp_keys; + struct tcf_pedit_parms *parms; - kfree(keys); - kfree(p->tcfp_keys_ex); + parms = rcu_dereference_protected(p->parms, 1); + + if (parms) + call_rcu(&parms->rcu, tcf_pedit_cleanup_rcu); } static bool offset_valid(struct sk_buff *skb, int offset) @@ -323,28 +345,30 @@ static int tcf_pedit_act(struct sk_buff *skb, const struct tc_action *a, struct tcf_result *res) { struct tcf_pedit *p = to_pedit(a); + struct tcf_pedit_parms *parms; u32 max_offset; int i; - spin_lock(&p->tcf_lock); + parms = rcu_dereference_bh(p->parms); max_offset = (skb_transport_header_was_set(skb) ? skb_transport_offset(skb) : skb_network_offset(skb)) + - p->tcfp_off_max_hint; + parms->tcfp_off_max_hint; if (skb_ensure_writable(skb, min(skb->len, max_offset))) - goto unlock; + goto done; tcf_lastuse_update(&p->tcf_tm); + tcf_action_update_bstats(&p->common, skb); - if (p->tcfp_nkeys > 0) { - struct tc_pedit_key *tkey = p->tcfp_keys; - struct tcf_pedit_key_ex *tkey_ex = p->tcfp_keys_ex; + if (parms->tcfp_nkeys > 0) { + struct tc_pedit_key *tkey = parms->tcfp_keys; + struct tcf_pedit_key_ex *tkey_ex = parms->tcfp_keys_ex; enum pedit_header_type htype = TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK; enum pedit_cmd cmd = TCA_PEDIT_KEY_EX_CMD_SET; - for (i = p->tcfp_nkeys; i > 0; i--, tkey++) { + for (i = parms->tcfp_nkeys; i > 0; i--, tkey++) { u32 *ptr, hdata; int offset = tkey->off; int hoffset; @@ -420,11 +444,10 @@ static int tcf_pedit_act(struct sk_buff *skb, const struct tc_action *a, } bad: + spin_lock(&p->tcf_lock); p->tcf_qstats.overlimits++; -done: - bstats_update(&p->tcf_bstats, skb); -unlock: spin_unlock(&p->tcf_lock); +done: return p->tcf_action; } @@ -443,30 +466,33 @@ static int tcf_pedit_dump(struct sk_buff *skb, struct tc_action *a, { unsigned char *b = skb_tail_pointer(skb); struct tcf_pedit *p = to_pedit(a); + struct tcf_pedit_parms *parms; struct tc_pedit *opt; struct tcf_t t; int s; - s = struct_size(opt, keys, p->tcfp_nkeys); - - /* netlink spinlocks held above us - must use ATOMIC */ - opt = kzalloc(s, GFP_ATOMIC); - if (unlikely(!opt)) - return -ENOBUFS; - spin_lock_bh(&p->tcf_lock); - memcpy(opt->keys, p->tcfp_keys, flex_array_size(opt, keys, p->tcfp_nkeys)); + parms = rcu_dereference_protected(p->parms, 1); + s = struct_size(opt, keys, parms->tcfp_nkeys); + + opt = kzalloc(s, GFP_ATOMIC); + if (unlikely(!opt)) { + spin_unlock_bh(&p->tcf_lock); + return -ENOBUFS; + } + + memcpy(opt->keys, parms->tcfp_keys, + flex_array_size(opt, keys, parms->tcfp_nkeys)); opt->index = p->tcf_index; - opt->nkeys = p->tcfp_nkeys; - opt->flags = p->tcfp_flags; + opt->nkeys = parms->tcfp_nkeys; + opt->flags = parms->tcfp_flags; opt->action = p->tcf_action; opt->refcnt = refcount_read(&p->tcf_refcnt) - ref; opt->bindcnt = atomic_read(&p->tcf_bindcnt) - bind; - if (p->tcfp_keys_ex) { - if (tcf_pedit_key_ex_dump(skb, - p->tcfp_keys_ex, - p->tcfp_nkeys)) + if (parms->tcfp_keys_ex) { + if (tcf_pedit_key_ex_dump(skb, parms->tcfp_keys_ex, + parms->tcfp_nkeys)) goto nla_put_failure; if (nla_put(skb, TCA_PEDIT_PARMS_EX, s, opt)) From 2cabfa2c404d50fa3e51d1e9424622c518096af1 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Fri, 24 Feb 2023 12:00:56 -0300 Subject: [PATCH 087/201] net/sched: act_pedit: fix action bind logic [ Upstream commit e9e42292ea76a8358b0c02ffd530d78e133a1b73 ] The TC architecture allows filters and actions to be created independently. In filters the user can reference action objects using: tc action add action pedit ... index 1 tc filter add ... action pedit index 1 In the current code for act_pedit this is broken as it checks netlink attributes for create/update before actually checking if we are binding to an existing action. tdc results: 1..69 ok 1 319a - Add pedit action that mangles IP TTL ok 2 7e67 - Replace pedit action with invalid goto chain ok 3 377e - Add pedit action with RAW_OP offset u32 ok 4 a0ca - Add pedit action with RAW_OP offset u32 (INVALID) ok 5 dd8a - Add pedit action with RAW_OP offset u16 u16 ok 6 53db - Add pedit action with RAW_OP offset u16 (INVALID) ok 7 5c7e - Add pedit action with RAW_OP offset u8 add value ok 8 2893 - Add pedit action with RAW_OP offset u8 quad ok 9 3a07 - Add pedit action with RAW_OP offset u8-u16-u8 ok 10 ab0f - Add pedit action with RAW_OP offset u16-u8-u8 ok 11 9d12 - Add pedit action with RAW_OP offset u32 set u16 clear u8 invert ok 12 ebfa - Add pedit action with RAW_OP offset overflow u32 (INVALID) ok 13 f512 - Add pedit action with RAW_OP offset u16 at offmask shift set ok 14 c2cb - Add pedit action with RAW_OP offset u32 retain value ok 15 1762 - Add pedit action with RAW_OP offset u8 clear value ok 16 bcee - Add pedit action with RAW_OP offset u8 retain value ok 17 e89f - Add pedit action with RAW_OP offset u16 retain value ok 18 c282 - Add pedit action with RAW_OP offset u32 clear value ok 19 c422 - Add pedit action with RAW_OP offset u16 invert value ok 20 d3d3 - Add pedit action with RAW_OP offset u32 invert value ok 21 57e5 - Add pedit action with RAW_OP offset u8 preserve value ok 22 99e0 - Add pedit action with RAW_OP offset u16 preserve value ok 23 1892 - Add pedit action with RAW_OP offset u32 preserve value ok 24 4b60 - Add pedit action with RAW_OP negative offset u16/u32 set value ok 25 a5a7 - Add pedit action with LAYERED_OP eth set src ok 26 86d4 - Add pedit action with LAYERED_OP eth set src & dst ok 27 f8a9 - Add pedit action with LAYERED_OP eth set dst ok 28 c715 - Add pedit action with LAYERED_OP eth set src (INVALID) ok 29 8131 - Add pedit action with LAYERED_OP eth set dst (INVALID) ok 30 ba22 - Add pedit action with LAYERED_OP eth type set/clear sequence ok 31 dec4 - Add pedit action with LAYERED_OP eth set type (INVALID) ok 32 ab06 - Add pedit action with LAYERED_OP eth add type ok 33 918d - Add pedit action with LAYERED_OP eth invert src ok 34 a8d4 - Add pedit action with LAYERED_OP eth invert dst ok 35 ee13 - Add pedit action with LAYERED_OP eth invert type ok 36 7588 - Add pedit action with LAYERED_OP ip set src ok 37 0fa7 - Add pedit action with LAYERED_OP ip set dst ok 38 5810 - Add pedit action with LAYERED_OP ip set src & dst ok 39 1092 - Add pedit action with LAYERED_OP ip set ihl & dsfield ok 40 02d8 - Add pedit action with LAYERED_OP ip set ttl & protocol ok 41 3e2d - Add pedit action with LAYERED_OP ip set ttl (INVALID) ok 42 31ae - Add pedit action with LAYERED_OP ip ttl clear/set ok 43 486f - Add pedit action with LAYERED_OP ip set duplicate fields ok 44 e790 - Add pedit action with LAYERED_OP ip set ce, df, mf, firstfrag, nofrag fields ok 45 cc8a - Add pedit action with LAYERED_OP ip set tos ok 46 7a17 - Add pedit action with LAYERED_OP ip set precedence ok 47 c3b6 - Add pedit action with LAYERED_OP ip add tos ok 48 43d3 - Add pedit action with LAYERED_OP ip add precedence ok 49 438e - Add pedit action with LAYERED_OP ip clear tos ok 50 6b1b - Add pedit action with LAYERED_OP ip clear precedence ok 51 824a - Add pedit action with LAYERED_OP ip invert tos ok 52 106f - Add pedit action with LAYERED_OP ip invert precedence ok 53 6829 - Add pedit action with LAYERED_OP beyond ip set dport & sport ok 54 afd8 - Add pedit action with LAYERED_OP beyond ip set icmp_type & icmp_code ok 55 3143 - Add pedit action with LAYERED_OP beyond ip set dport (INVALID) ok 56 815c - Add pedit action with LAYERED_OP ip6 set src ok 57 4dae - Add pedit action with LAYERED_OP ip6 set dst ok 58 fc1f - Add pedit action with LAYERED_OP ip6 set src & dst ok 59 6d34 - Add pedit action with LAYERED_OP ip6 dst retain value (INVALID) ok 60 94bb - Add pedit action with LAYERED_OP ip6 traffic_class ok 61 6f5e - Add pedit action with LAYERED_OP ip6 flow_lbl ok 62 6795 - Add pedit action with LAYERED_OP ip6 set payload_len, nexthdr, hoplimit ok 63 1442 - Add pedit action with LAYERED_OP tcp set dport & sport ok 64 b7ac - Add pedit action with LAYERED_OP tcp sport set (INVALID) ok 65 cfcc - Add pedit action with LAYERED_OP tcp flags set ok 66 3bc4 - Add pedit action with LAYERED_OP tcp set dport, sport & flags fields ok 67 f1c8 - Add pedit action with LAYERED_OP udp set dport & sport ok 68 d784 - Add pedit action with mixed RAW/LAYERED_OP #1 ok 69 70ca - Add pedit action with mixed RAW/LAYERED_OP #2 Fixes: 71d0ed7079df ("net/act_pedit: Support using offset relative to the conventional network headers") Fixes: f67169fef8db ("net/sched: act_pedit: fix WARN() in the traffic path") Reviewed-by: Jamal Hadi Salim Signed-off-by: Pedro Tammela Reviewed-by: Simon Horman Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/sched/act_pedit.c | 58 +++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index 655addb31b7f..238759c3192e 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -180,26 +180,6 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, } parm = nla_data(pattr); - if (!parm->nkeys) { - NL_SET_ERR_MSG_MOD(extack, "Pedit requires keys to be passed"); - return -EINVAL; - } - ksize = parm->nkeys * sizeof(struct tc_pedit_key); - if (nla_len(pattr) < sizeof(*parm) + ksize) { - NL_SET_ERR_MSG_ATTR(extack, pattr, "Length of TCA_PEDIT_PARMS or TCA_PEDIT_PARMS_EX pedit attribute is invalid"); - return -EINVAL; - } - - nparms = kzalloc(sizeof(*nparms), GFP_KERNEL); - if (!nparms) - return -ENOMEM; - - nparms->tcfp_keys_ex = - tcf_pedit_keys_ex_parse(tb[TCA_PEDIT_KEYS_EX], parm->nkeys); - if (IS_ERR(nparms->tcfp_keys_ex)) { - ret = PTR_ERR(nparms->tcfp_keys_ex); - goto out_free; - } index = parm->index; err = tcf_idr_check_alloc(tn, &index, a, bind); @@ -208,25 +188,49 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, &act_pedit_ops, bind, flags); if (ret) { tcf_idr_cleanup(tn, index); - goto out_free_ex; + return ret; } ret = ACT_P_CREATED; } else if (err > 0) { if (bind) - goto out_free; + return 0; if (!(flags & TCA_ACT_FLAGS_REPLACE)) { ret = -EEXIST; goto out_release; } } else { - ret = err; - goto out_free_ex; + return err; + } + + if (!parm->nkeys) { + NL_SET_ERR_MSG_MOD(extack, "Pedit requires keys to be passed"); + ret = -EINVAL; + goto out_release; + } + ksize = parm->nkeys * sizeof(struct tc_pedit_key); + if (nla_len(pattr) < sizeof(*parm) + ksize) { + NL_SET_ERR_MSG_ATTR(extack, pattr, "Length of TCA_PEDIT_PARMS or TCA_PEDIT_PARMS_EX pedit attribute is invalid"); + ret = -EINVAL; + goto out_release; + } + + nparms = kzalloc(sizeof(*nparms), GFP_KERNEL); + if (!nparms) { + ret = -ENOMEM; + goto out_release; + } + + nparms->tcfp_keys_ex = + tcf_pedit_keys_ex_parse(tb[TCA_PEDIT_KEYS_EX], parm->nkeys); + if (IS_ERR(nparms->tcfp_keys_ex)) { + ret = PTR_ERR(nparms->tcfp_keys_ex); + goto out_free; } err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); if (err < 0) { ret = err; - goto out_release; + goto out_free_ex; } nparms->tcfp_off_max_hint = 0; @@ -277,12 +281,12 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, put_chain: if (goto_ch) tcf_chain_put_by_act(goto_ch); -out_release: - tcf_idr_release(*a, bind); out_free_ex: kfree(nparms->tcfp_keys_ex); out_free: kfree(nparms); +out_release: + tcf_idr_release(*a, bind); return ret; } From af8bfc1add67309607b51e8758b86b42690b86c1 Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Fri, 24 Feb 2023 12:00:57 -0300 Subject: [PATCH 088/201] net/sched: act_mpls: fix action bind logic [ Upstream commit e88d78a773cb5242e933930c8855bf4b2e8c2397 ] The TC architecture allows filters and actions to be created independently. In filters the user can reference action objects using: tc action add action mpls ... index 1 tc filter add ... action mpls index 1 In the current code for act_mpls this is broken as it checks netlink attributes for create/update before actually checking if we are binding to an existing action. tdc results: 1..53 ok 1 a933 - Add MPLS dec_ttl action with pipe opcode ok 2 08d1 - Add mpls dec_ttl action with pass opcode ok 3 d786 - Add mpls dec_ttl action with drop opcode ok 4 f334 - Add mpls dec_ttl action with reclassify opcode ok 5 29bd - Add mpls dec_ttl action with continue opcode ok 6 48df - Add mpls dec_ttl action with jump opcode ok 7 62eb - Add mpls dec_ttl action with trap opcode ok 8 09d2 - Add mpls dec_ttl action with opcode and cookie ok 9 c170 - Add mpls dec_ttl action with opcode and cookie of max length ok 10 9118 - Add mpls dec_ttl action with invalid opcode ok 11 6ce1 - Add mpls dec_ttl action with label (invalid) ok 12 352f - Add mpls dec_ttl action with tc (invalid) ok 13 fa1c - Add mpls dec_ttl action with ttl (invalid) ok 14 6b79 - Add mpls dec_ttl action with bos (invalid) ok 15 d4c4 - Add mpls pop action with ip proto ok 16 91fb - Add mpls pop action with ip proto and cookie ok 17 92fe - Add mpls pop action with mpls proto ok 18 7e23 - Add mpls pop action with no protocol (invalid) ok 19 6182 - Add mpls pop action with label (invalid) ok 20 6475 - Add mpls pop action with tc (invalid) ok 21 067b - Add mpls pop action with ttl (invalid) ok 22 7316 - Add mpls pop action with bos (invalid) ok 23 38cc - Add mpls push action with label ok 24 c281 - Add mpls push action with mpls_mc protocol ok 25 5db4 - Add mpls push action with label, tc and ttl ok 26 7c34 - Add mpls push action with label, tc ttl and cookie of max length ok 27 16eb - Add mpls push action with label and bos ok 28 d69d - Add mpls push action with no label (invalid) ok 29 e8e4 - Add mpls push action with ipv4 protocol (invalid) ok 30 ecd0 - Add mpls push action with out of range label (invalid) ok 31 d303 - Add mpls push action with out of range tc (invalid) ok 32 fd6e - Add mpls push action with ttl of 0 (invalid) ok 33 19e9 - Add mpls mod action with mpls label ok 34 1fde - Add mpls mod action with max mpls label ok 35 0c50 - Add mpls mod action with mpls label exceeding max (invalid) ok 36 10b6 - Add mpls mod action with mpls label of MPLS_LABEL_IMPLNULL (invalid) ok 37 57c9 - Add mpls mod action with mpls min tc ok 38 6872 - Add mpls mod action with mpls max tc ok 39 a70a - Add mpls mod action with mpls tc exceeding max (invalid) ok 40 6ed5 - Add mpls mod action with mpls ttl ok 41 77c1 - Add mpls mod action with mpls ttl and cookie ok 42 b80f - Add mpls mod action with mpls max ttl ok 43 8864 - Add mpls mod action with mpls min ttl ok 44 6c06 - Add mpls mod action with mpls ttl of 0 (invalid) ok 45 b5d8 - Add mpls mod action with mpls ttl exceeding max (invalid) ok 46 451f - Add mpls mod action with mpls max bos ok 47 a1ed - Add mpls mod action with mpls min bos ok 48 3dcf - Add mpls mod action with mpls bos exceeding max (invalid) ok 49 db7c - Add mpls mod action with protocol (invalid) ok 50 b070 - Replace existing mpls push action with new ID ok 51 95a9 - Replace existing mpls push action with new label, tc, ttl and cookie ok 52 6cce - Delete mpls pop action ok 53 d138 - Flush mpls actions Fixes: 2a2ea50870ba ("net: sched: add mpls manipulation actions to TC") Reviewed-by: Jamal Hadi Salim Signed-off-by: Pedro Tammela Reviewed-by: Simon Horman Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/sched/act_mpls.c | 66 +++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/net/sched/act_mpls.c b/net/sched/act_mpls.c index ea5959094adb..f24f997a7aaf 100644 --- a/net/sched/act_mpls.c +++ b/net/sched/act_mpls.c @@ -188,40 +188,67 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla, parm = nla_data(tb[TCA_MPLS_PARMS]); index = parm->index; + err = tcf_idr_check_alloc(tn, &index, a, bind); + if (err < 0) + return err; + exists = err; + if (exists && bind) + return 0; + + if (!exists) { + ret = tcf_idr_create(tn, index, est, a, &act_mpls_ops, bind, + true, flags); + if (ret) { + tcf_idr_cleanup(tn, index); + return ret; + } + + ret = ACT_P_CREATED; + } else if (!(flags & TCA_ACT_FLAGS_REPLACE)) { + tcf_idr_release(*a, bind); + return -EEXIST; + } + /* Verify parameters against action type. */ switch (parm->m_action) { case TCA_MPLS_ACT_POP: if (!tb[TCA_MPLS_PROTO]) { NL_SET_ERR_MSG_MOD(extack, "Protocol must be set for MPLS pop"); - return -EINVAL; + err = -EINVAL; + goto release_idr; } if (!eth_proto_is_802_3(nla_get_be16(tb[TCA_MPLS_PROTO]))) { NL_SET_ERR_MSG_MOD(extack, "Invalid protocol type for MPLS pop"); - return -EINVAL; + err = -EINVAL; + goto release_idr; } if (tb[TCA_MPLS_LABEL] || tb[TCA_MPLS_TTL] || tb[TCA_MPLS_TC] || tb[TCA_MPLS_BOS]) { NL_SET_ERR_MSG_MOD(extack, "Label, TTL, TC or BOS cannot be used with MPLS pop"); - return -EINVAL; + err = -EINVAL; + goto release_idr; } break; case TCA_MPLS_ACT_DEC_TTL: if (tb[TCA_MPLS_PROTO] || tb[TCA_MPLS_LABEL] || tb[TCA_MPLS_TTL] || tb[TCA_MPLS_TC] || tb[TCA_MPLS_BOS]) { NL_SET_ERR_MSG_MOD(extack, "Label, TTL, TC, BOS or protocol cannot be used with MPLS dec_ttl"); - return -EINVAL; + err = -EINVAL; + goto release_idr; } break; case TCA_MPLS_ACT_PUSH: case TCA_MPLS_ACT_MAC_PUSH: if (!tb[TCA_MPLS_LABEL]) { NL_SET_ERR_MSG_MOD(extack, "Label is required for MPLS push"); - return -EINVAL; + err = -EINVAL; + goto release_idr; } if (tb[TCA_MPLS_PROTO] && !eth_p_mpls(nla_get_be16(tb[TCA_MPLS_PROTO]))) { NL_SET_ERR_MSG_MOD(extack, "Protocol must be an MPLS type for MPLS push"); - return -EPROTONOSUPPORT; + err = -EPROTONOSUPPORT; + goto release_idr; } /* Push needs a TTL - if not specified, set a default value. */ if (!tb[TCA_MPLS_TTL]) { @@ -236,33 +263,14 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla, case TCA_MPLS_ACT_MODIFY: if (tb[TCA_MPLS_PROTO]) { NL_SET_ERR_MSG_MOD(extack, "Protocol cannot be used with MPLS modify"); - return -EINVAL; + err = -EINVAL; + goto release_idr; } break; default: NL_SET_ERR_MSG_MOD(extack, "Unknown MPLS action"); - return -EINVAL; - } - - err = tcf_idr_check_alloc(tn, &index, a, bind); - if (err < 0) - return err; - exists = err; - if (exists && bind) - return 0; - - if (!exists) { - ret = tcf_idr_create(tn, index, est, a, - &act_mpls_ops, bind, true, flags); - if (ret) { - tcf_idr_cleanup(tn, index); - return ret; - } - - ret = ACT_P_CREATED; - } else if (!(flags & TCA_ACT_FLAGS_REPLACE)) { - tcf_idr_release(*a, bind); - return -EEXIST; + err = -EINVAL; + goto release_idr; } err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); From 113d2d158f2468ab8f9674adcc81b67dedc2524a Mon Sep 17 00:00:00 2001 From: Pedro Tammela Date: Fri, 24 Feb 2023 12:00:58 -0300 Subject: [PATCH 089/201] net/sched: act_sample: fix action bind logic [ Upstream commit 4a20056a49a1854966562241922f68197f950539 ] The TC architecture allows filters and actions to be created independently. In filters the user can reference action objects using: tc action add action sample ... index 1 tc filter add ... action pedit index 1 In the current code for act_sample this is broken as it checks netlink attributes for create/update before actually checking if we are binding to an existing action. tdc results: 1..29 ok 1 9784 - Add valid sample action with mandatory arguments ok 2 5c91 - Add valid sample action with mandatory arguments and continue control action ok 3 334b - Add valid sample action with mandatory arguments and drop control action ok 4 da69 - Add valid sample action with mandatory arguments and reclassify control action ok 5 13ce - Add valid sample action with mandatory arguments and pipe control action ok 6 1886 - Add valid sample action with mandatory arguments and jump control action ok 7 7571 - Add sample action with invalid rate ok 8 b6d4 - Add sample action with mandatory arguments and invalid control action ok 9 a874 - Add invalid sample action without mandatory arguments ok 10 ac01 - Add invalid sample action without mandatory argument rate ok 11 4203 - Add invalid sample action without mandatory argument group ok 12 14a7 - Add invalid sample action without mandatory argument group ok 13 8f2e - Add valid sample action with trunc argument ok 14 45f8 - Add sample action with maximum rate argument ok 15 ad0c - Add sample action with maximum trunc argument ok 16 83a9 - Add sample action with maximum group argument ok 17 ed27 - Add sample action with invalid rate argument ok 18 2eae - Add sample action with invalid group argument ok 19 6ff3 - Add sample action with invalid trunc size ok 20 2b2a - Add sample action with invalid index ok 21 dee2 - Add sample action with maximum allowed index ok 22 560e - Add sample action with cookie ok 23 704a - Replace existing sample action with new rate argument ok 24 60eb - Replace existing sample action with new group argument ok 25 2cce - Replace existing sample action with new trunc argument ok 26 59d1 - Replace existing sample action with new control argument ok 27 0a6e - Replace sample action with invalid goto chain control ok 28 3872 - Delete sample action with valid index ok 29 a394 - Delete sample action with invalid index Fixes: 5c5670fae430 ("net/sched: Introduce sample tc action") Reviewed-by: Jamal Hadi Salim Signed-off-by: Pedro Tammela Reviewed-by: Simon Horman Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/sched/act_sample.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c index 7a25477f5d99..09735a33e57e 100644 --- a/net/sched/act_sample.c +++ b/net/sched/act_sample.c @@ -54,8 +54,8 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla, sample_policy, NULL); if (ret < 0) return ret; - if (!tb[TCA_SAMPLE_PARMS] || !tb[TCA_SAMPLE_RATE] || - !tb[TCA_SAMPLE_PSAMPLE_GROUP]) + + if (!tb[TCA_SAMPLE_PARMS]) return -EINVAL; parm = nla_data(tb[TCA_SAMPLE_PARMS]); @@ -79,6 +79,13 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla, tcf_idr_release(*a, bind); return -EEXIST; } + + if (!tb[TCA_SAMPLE_RATE] || !tb[TCA_SAMPLE_PSAMPLE_GROUP]) { + NL_SET_ERR_MSG(extack, "sample rate and group are required"); + err = -EINVAL; + goto release_idr; + } + err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); if (err < 0) goto release_idr; From 9df677d781303279fd577ed57557ba6e93d3cb85 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Fri, 24 Feb 2023 17:52:33 +0200 Subject: [PATCH 090/201] net: dsa: seville: ignore mscc-miim read errors from Lynx PCS [ Upstream commit 0322ef49c1ac6f0e2ef37b146c0bf8440873072c ] During the refactoring in the commit below, vsc9953_mdio_read() was replaced with mscc_miim_read(), which has one extra step: it checks for the MSCC_MIIM_DATA_ERROR bits before returning the result. On T1040RDB, there are 8 QSGMII PCSes belonging to the switch, and they are organized in 2 groups. First group responds to MDIO addresses 4-7 because QSGMIIACR1[MDEV_PORT] is 1, and the second group responds to MDIO addresses 8-11 because QSGMIIBCR1[MDEV_PORT] is 2. I have double checked that these values are correctly set in the SERDES, as well as PCCR1[QSGMA_CFG] and PCCR1[QSGMB_CFG] are both 0b01. mscc_miim_read: phyad 8 reg 0x1 MIIM_DATA 0x2d mscc_miim_read: phyad 8 reg 0x5 MIIM_DATA 0x5801 mscc_miim_read: phyad 8 reg 0x1 MIIM_DATA 0x2d mscc_miim_read: phyad 8 reg 0x5 MIIM_DATA 0x5801 mscc_miim_read: phyad 9 reg 0x1 MIIM_DATA 0x2d mscc_miim_read: phyad 9 reg 0x5 MIIM_DATA 0x5801 mscc_miim_read: phyad 9 reg 0x1 MIIM_DATA 0x2d mscc_miim_read: phyad 9 reg 0x5 MIIM_DATA 0x5801 mscc_miim_read: phyad 10 reg 0x1 MIIM_DATA 0x2d mscc_miim_read: phyad 10 reg 0x5 MIIM_DATA 0x5801 mscc_miim_read: phyad 10 reg 0x1 MIIM_DATA 0x2d mscc_miim_read: phyad 10 reg 0x5 MIIM_DATA 0x5801 mscc_miim_read: phyad 11 reg 0x1 MIIM_DATA 0x2d mscc_miim_read: phyad 11 reg 0x5 MIIM_DATA 0x5801 mscc_miim_read: phyad 11 reg 0x1 MIIM_DATA 0x2d mscc_miim_read: phyad 11 reg 0x5 MIIM_DATA 0x5801 mscc_miim_read: phyad 4 reg 0x1 MIIM_DATA 0x3002d, ERROR mscc_miim_read: phyad 4 reg 0x5 MIIM_DATA 0x3da01, ERROR mscc_miim_read: phyad 5 reg 0x1 MIIM_DATA 0x3002d, ERROR mscc_miim_read: phyad 5 reg 0x5 MIIM_DATA 0x35801, ERROR mscc_miim_read: phyad 5 reg 0x1 MIIM_DATA 0x3002d, ERROR mscc_miim_read: phyad 5 reg 0x5 MIIM_DATA 0x35801, ERROR mscc_miim_read: phyad 6 reg 0x1 MIIM_DATA 0x3002d, ERROR mscc_miim_read: phyad 6 reg 0x5 MIIM_DATA 0x35801, ERROR mscc_miim_read: phyad 6 reg 0x1 MIIM_DATA 0x3002d, ERROR mscc_miim_read: phyad 6 reg 0x5 MIIM_DATA 0x35801, ERROR mscc_miim_read: phyad 7 reg 0x1 MIIM_DATA 0x3002d, ERROR mscc_miim_read: phyad 7 reg 0x5 MIIM_DATA 0x35801, ERROR mscc_miim_read: phyad 7 reg 0x1 MIIM_DATA 0x3002d, ERROR mscc_miim_read: phyad 7 reg 0x5 MIIM_DATA 0x35801, ERROR As can be seen, the data in MIIM_DATA is still valid despite having the MSCC_MIIM_DATA_ERROR bits set. The driver as introduced in commit 84705fc16552 ("net: dsa: felix: introduce support for Seville VSC9953 switch") was ignoring these bits, perhaps deliberately (although unbeknownst to me). This is an old IP and the hardware team cannot seem to be able to help me track down a plausible reason for these failures. I'll keep investigating, but in the meantime, this is a direct regression which must be restored to a working state. The only thing I can do is keep ignoring the errors as before. Fixes: b99658452355 ("net: dsa: ocelot: felix: utilize shared mscc-miim driver for indirect MDIO access") Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/dsa/ocelot/seville_vsc9953.c | 4 ++-- drivers/net/mdio/mdio-mscc-miim.c | 9 ++++++--- include/linux/mdio/mdio-mscc-miim.h | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c index 7af33b2c685d..c2863d6d870f 100644 --- a/drivers/net/dsa/ocelot/seville_vsc9953.c +++ b/drivers/net/dsa/ocelot/seville_vsc9953.c @@ -923,8 +923,8 @@ static int vsc9953_mdio_bus_alloc(struct ocelot *ocelot) rc = mscc_miim_setup(dev, &bus, "VSC9953 internal MDIO bus", ocelot->targets[GCB], - ocelot->map[GCB][GCB_MIIM_MII_STATUS & REG_MASK]); - + ocelot->map[GCB][GCB_MIIM_MII_STATUS & REG_MASK], + true); if (rc) { dev_err(dev, "failed to setup MDIO bus\n"); return rc; diff --git a/drivers/net/mdio/mdio-mscc-miim.c b/drivers/net/mdio/mdio-mscc-miim.c index 51f68daac152..34b87389788b 100644 --- a/drivers/net/mdio/mdio-mscc-miim.c +++ b/drivers/net/mdio/mdio-mscc-miim.c @@ -52,6 +52,7 @@ struct mscc_miim_info { struct mscc_miim_dev { struct regmap *regs; int mii_status_offset; + bool ignore_read_errors; struct regmap *phy_regs; const struct mscc_miim_info *info; struct clk *clk; @@ -138,7 +139,7 @@ static int mscc_miim_read(struct mii_bus *bus, int mii_id, int regnum) goto out; } - if (val & MSCC_MIIM_DATA_ERROR) { + if (!miim->ignore_read_errors && !!(val & MSCC_MIIM_DATA_ERROR)) { ret = -EIO; goto out; } @@ -218,7 +219,8 @@ static const struct regmap_config mscc_miim_phy_regmap_config = { }; int mscc_miim_setup(struct device *dev, struct mii_bus **pbus, const char *name, - struct regmap *mii_regmap, int status_offset) + struct regmap *mii_regmap, int status_offset, + bool ignore_read_errors) { struct mscc_miim_dev *miim; struct mii_bus *bus; @@ -240,6 +242,7 @@ int mscc_miim_setup(struct device *dev, struct mii_bus **pbus, const char *name, miim->regs = mii_regmap; miim->mii_status_offset = status_offset; + miim->ignore_read_errors = ignore_read_errors; *pbus = bus; @@ -291,7 +294,7 @@ static int mscc_miim_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(phy_regmap), "Unable to create phy register regmap\n"); - ret = mscc_miim_setup(dev, &bus, "mscc_miim", mii_regmap, 0); + ret = mscc_miim_setup(dev, &bus, "mscc_miim", mii_regmap, 0, false); if (ret < 0) { dev_err(dev, "Unable to setup the MDIO bus\n"); return ret; diff --git a/include/linux/mdio/mdio-mscc-miim.h b/include/linux/mdio/mdio-mscc-miim.h index 5b4ed2c3cbb9..1ce699740af6 100644 --- a/include/linux/mdio/mdio-mscc-miim.h +++ b/include/linux/mdio/mdio-mscc-miim.h @@ -14,6 +14,6 @@ int mscc_miim_setup(struct device *device, struct mii_bus **bus, const char *name, struct regmap *mii_regmap, - int status_offset); + int status_offset, bool ignore_read_errors); #endif From df2dac168c74eaa5f48e0415564965eb76ba1657 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Fri, 24 Feb 2023 17:52:34 +0200 Subject: [PATCH 091/201] net: dsa: felix: fix internal MDIO controller resource length [ Upstream commit 940af261321307cd1dd0fe8f9c34a6129f9d4bdc ] The blamed commit did not properly convert the resource start/end format into the DEFINE_RES_MEM_NAMED() start/length format, resulting in a resource for vsc9959_imdio_res which is much longer than expected: $ cat /proc/iomem 1f8000000-1f815ffff : pcie@1f0000000 1f8140000-1f815ffff : 0000:00:00.5 1f8148030-1f815006f : imdio vs (correct) $ cat /proc/iomem 1f8000000-1f815ffff : pcie@1f0000000 1f8140000-1f815ffff : 0000:00:00.5 1f8148030-1f814803f : imdio Luckily it's not big enough to exceed the size of the parent resource (pci_resource_end(pdev, VSC9959_IMDIO_PCI_BAR)), and it doesn't overlap with anything else that the Linux driver uses currently, so the larger than expected size isn't a practical problem that I can see. Although it is clearly wrong in the /proc/iomem output. Fixes: 044d447a801f ("net: dsa: felix: use DEFINE_RES_MEM_NAMED for resources") Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/dsa/ocelot/felix_vsc9959.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index 26a35ae322d1..cc89cff029e1 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -513,7 +513,7 @@ static const char * const vsc9959_resource_names[TARGET_MAX] = { * SGMII/QSGMII MAC PCS can be found. */ static const struct resource vsc9959_imdio_res = - DEFINE_RES_MEM_NAMED(0x8030, 0x8040, "imdio"); + DEFINE_RES_MEM_NAMED(0x8030, 0x10, "imdio"); static const struct reg_field vsc9959_regfields[REGFIELD_MAX] = { [ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 6, 6), From fb987e7a9bd047ab5c901371a7e6c40f53fecfaf Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 25 Feb 2023 17:22:37 +0100 Subject: [PATCH 092/201] ARM: dts: spear320-hmi: correct STMPE GPIO compatible [ Upstream commit 33a0c1b850c8c85f400531dab3a0b022cdb164b1 ] The compatible is st,stmpe-gpio. Fixes: e2eb69183ec4 ("ARM: SPEAr320: DT: Add SPEAr 320 HMI board support") Signed-off-by: Krzysztof Kozlowski Acked-by: Viresh Kumar Link: https://lore.kernel.org/r/20230225162237.40242-1-krzysztof.kozlowski@linaro.org Signed-off-by: Arnd Bergmann Signed-off-by: Sasha Levin --- arch/arm/boot/dts/spear320-hmi.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/spear320-hmi.dts b/arch/arm/boot/dts/spear320-hmi.dts index 34503ac9c51c..721e5ee7b680 100644 --- a/arch/arm/boot/dts/spear320-hmi.dts +++ b/arch/arm/boot/dts/spear320-hmi.dts @@ -241,7 +241,7 @@ irq-trigger = <0x1>; stmpegpio: stmpe-gpio { - compatible = "stmpe,gpio"; + compatible = "st,stmpe-gpio"; reg = <0>; gpio-controller; #gpio-cells = <2>; From 95c131b41f003009cef96dd499be034a73e6bb44 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 27 Feb 2023 08:33:36 +0000 Subject: [PATCH 093/201] tcp: tcp_check_req() can be called from process context [ Upstream commit 580f98cc33a260bb8c6a39ae2921b29586b84fdf ] This is a follow up of commit 0a375c822497 ("tcp: tcp_rtx_synack() can be called from process context"). Frederick Lawler reported another "__this_cpu_add() in preemptible" warning caused by the same reason. In my former patch I took care of tcp_rtx_synack() but forgot that tcp_check_req() also contained some SNMP updates. Note that some parts of tcp_check_req() always run in BH context, I added a comment to clarify this. Fixes: 8336886f786f ("tcp: TCP Fast Open Server - support TFO listeners") Link: https://lore.kernel.org/netdev/8cd33923-a21d-397c-e46b-2a068c287b03@cloudflare.com/T/ Signed-off-by: Eric Dumazet Reported-by: Frederick Lawler Tested-by: Frederick Lawler Link: https://lore.kernel.org/r/20230227083336.4153089-1-edumazet@google.com Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/ipv4/tcp_minisocks.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index c375f603a16c..7f37e7da6467 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -580,6 +580,9 @@ EXPORT_SYMBOL(tcp_create_openreq_child); * validation and inside tcp_v4_reqsk_send_ack(). Can we do better? * * We don't need to initialize tmp_opt.sack_ok as we don't use the results + * + * Note: If @fastopen is true, this can be called from process context. + * Otherwise, this is from BH context. */ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, @@ -731,7 +734,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, &tcp_rsk(req)->last_oow_ack_time)) req->rsk_ops->send_ack(sk, skb, req); if (paws_reject) - __NET_INC_STATS(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED); + NET_INC_STATS(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED); return NULL; } @@ -750,7 +753,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, * "fourth, check the SYN bit" */ if (flg & (TCP_FLAG_RST|TCP_FLAG_SYN)) { - __TCP_INC_STATS(sock_net(sk), TCP_MIB_ATTEMPTFAILS); + TCP_INC_STATS(sock_net(sk), TCP_MIB_ATTEMPTFAILS); goto embryonic_reset; } From d6e15f8de5b5efd6ecde9bd5cd52d4b60982ba22 Mon Sep 17 00:00:00 2001 From: George Kennedy Date: Mon, 27 Feb 2023 15:21:41 -0500 Subject: [PATCH 094/201] vc_screen: modify vcs_size() handling in vcs_read() [ Upstream commit 46d733d0efc79bc8430d63b57ab88011806d5180 ] Restore the vcs_size() handling in vcs_read() to what it had been in previous version. Fixes: 226fae124b2d ("vc_screen: move load of struct vc_data pointer in vcs_read() to avoid UAF") Suggested-by: Jiri Slaby Signed-off-by: George Kennedy Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin --- drivers/tty/vt/vc_screen.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index 71e091f879f0..1dc07f9214d5 100644 --- a/drivers/tty/vt/vc_screen.c +++ b/drivers/tty/vt/vc_screen.c @@ -415,10 +415,8 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) */ size = vcs_size(vc, attr, uni_mode); if (size < 0) { - if (read) - break; ret = size; - goto unlock_out; + break; } if (pos >= size) break; From aa7dc954e809c03383b7a4b3e5ad5ba7f64e4b28 Mon Sep 17 00:00:00 2001 From: Krishna Yarlagadda Date: Tue, 28 Feb 2023 01:34:28 +0530 Subject: [PATCH 095/201] spi: tegra210-quad: Fix iterator outside loop [ Upstream commit 2449d436681d40bc63ec2c766fd51b632270d8a7 ] Fix warn: iterator used outside loop: 'xfer'. 'xfer' variable contain invalid value in few conditions. Complete transfer within DATA phase in successful case and at the end for failed transfer. Reported-by: Dan Carpenter Link:https://lore.kernel.org/all/202210191211.46FkzKmv-lkp@intel.com/ Fixes: 8777dd9dff40 ("spi: tegra210-quad: Fix combined sequence") Signed-off-by: Krishna Yarlagadda Link: https://lore.kernel.org/r/20230227200428.45832-1-kyarlagadda@nvidia.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spi-tegra210-quad.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c index 6498948e150a..06c54d49076a 100644 --- a/drivers/spi/spi-tegra210-quad.c +++ b/drivers/spi/spi-tegra210-quad.c @@ -1156,6 +1156,10 @@ static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi, ret = -EIO; goto exit; } + if (!xfer->cs_change) { + tegra_qspi_transfer_end(spi); + spi_transfer_delay_exec(xfer); + } break; default: ret = -EINVAL; @@ -1164,14 +1168,14 @@ static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi, msg->actual_length += xfer->len; transfer_phase++; } - if (!xfer->cs_change) { - tegra_qspi_transfer_end(spi); - spi_transfer_delay_exec(xfer); - } ret = 0; exit: msg->status = ret; + if (ret < 0) { + tegra_qspi_transfer_end(spi); + spi_transfer_delay_exec(xfer); + } return ret; } From 9425d1ee2c0c27d0ede841dd413c261cf91aa740 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Thu, 29 Dec 2022 15:53:19 -0600 Subject: [PATCH 096/201] rtc: sun6i: Always export the internal oscillator [ Upstream commit 344f4030f6c50a9db2d03021884c4bf36191b53a ] On all variants of the hardware, the internal oscillator is one possible parent for the AR100 clock. It needs to be exported so we can model that relationship correctly in the devicetree. Fixes: c56afc1844d6 ("rtc: sun6i: Expose internal oscillator through device tree") Signed-off-by: Samuel Holland Acked-by: Jernej Skrabec Link: https://lore.kernel.org/r/20221229215319.14145-1-samuel@sholland.org Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin --- drivers/rtc/rtc-sun6i.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c index ed5516089e9a..7038f47d77ff 100644 --- a/drivers/rtc/rtc-sun6i.c +++ b/drivers/rtc/rtc-sun6i.c @@ -136,7 +136,6 @@ struct sun6i_rtc_clk_data { unsigned int fixed_prescaler : 16; unsigned int has_prescaler : 1; unsigned int has_out_clk : 1; - unsigned int export_iosc : 1; unsigned int has_losc_en : 1; unsigned int has_auto_swt : 1; }; @@ -271,10 +270,8 @@ static void __init sun6i_rtc_clk_init(struct device_node *node, /* Yes, I know, this is ugly. */ sun6i_rtc = rtc; - /* Only read IOSC name from device tree if it is exported */ - if (rtc->data->export_iosc) - of_property_read_string_index(node, "clock-output-names", 2, - &iosc_name); + of_property_read_string_index(node, "clock-output-names", 2, + &iosc_name); rtc->int_osc = clk_hw_register_fixed_rate_with_accuracy(NULL, iosc_name, @@ -315,13 +312,10 @@ static void __init sun6i_rtc_clk_init(struct device_node *node, goto err_register; } - clk_data->num = 2; + clk_data->num = 3; clk_data->hws[0] = &rtc->hw; clk_data->hws[1] = __clk_get_hw(rtc->ext_losc); - if (rtc->data->export_iosc) { - clk_data->hws[2] = rtc->int_osc; - clk_data->num = 3; - } + clk_data->hws[2] = rtc->int_osc; of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); return; @@ -361,7 +355,6 @@ static const struct sun6i_rtc_clk_data sun8i_h3_rtc_data = { .fixed_prescaler = 32, .has_prescaler = 1, .has_out_clk = 1, - .export_iosc = 1, }; static void __init sun8i_h3_rtc_clk_init(struct device_node *node) @@ -379,7 +372,6 @@ static const struct sun6i_rtc_clk_data sun50i_h6_rtc_data = { .fixed_prescaler = 32, .has_prescaler = 1, .has_out_clk = 1, - .export_iosc = 1, .has_losc_en = 1, .has_auto_swt = 1, }; From 926aef60ea64cd9becf2829f7388f48dbe8bcb11 Mon Sep 17 00:00:00 2001 From: Sergey Shtylyov Date: Wed, 17 Aug 2022 23:00:45 +0300 Subject: [PATCH 097/201] genirq/ipi: Fix NULL pointer deref in irq_data_get_affinity_mask() [ Upstream commit feabecaff5902f896531dde90646ca5dfa9d4f7d ] If ipi_send_{mask|single}() is called with an invalid interrupt number, all the local variables there will be NULL. ipi_send_verify() which is invoked from these functions does verify its 'data' parameter, resulting in a kernel oops in irq_data_get_affinity_mask() as the passed NULL pointer gets dereferenced. Add a missing NULL pointer check in ipi_send_verify()... Found by Linux Verification Center (linuxtesting.org) with the SVACE static analysis tool. Fixes: 3b8e29a82dd1 ("genirq: Implement ipi_send_mask/single()") Signed-off-by: Sergey Shtylyov Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/r/b541232d-c2b6-1fe9-79b4-a7129459e4d0@omp.ru Signed-off-by: Sasha Levin --- kernel/irq/ipi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/kernel/irq/ipi.c b/kernel/irq/ipi.c index bbd945bacef0..961d4af76af3 100644 --- a/kernel/irq/ipi.c +++ b/kernel/irq/ipi.c @@ -188,9 +188,9 @@ EXPORT_SYMBOL_GPL(ipi_get_hwirq); static int ipi_send_verify(struct irq_chip *chip, struct irq_data *data, const struct cpumask *dest, unsigned int cpu) { - const struct cpumask *ipimask = irq_data_get_affinity_mask(data); + const struct cpumask *ipimask; - if (!chip || !ipimask) + if (!chip || !data) return -EINVAL; if (!chip->ipi_send_single && !chip->ipi_send_mask) @@ -199,6 +199,10 @@ static int ipi_send_verify(struct irq_chip *chip, struct irq_data *data, if (cpu >= nr_cpu_ids) return -EINVAL; + ipimask = irq_data_get_affinity_mask(data); + if (!ipimask) + return -EINVAL; + if (dest) { if (!cpumask_subset(dest, ipimask)) return -EINVAL; From 66050599b980d8bca0d3bd498fe4065e523f3995 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 14 Feb 2023 14:28:08 +0100 Subject: [PATCH 098/201] scsi: ipr: Work around fortify-string warning [ Upstream commit ee4e7dfe4ffc9ca50c6875757bd119abfe22b5c5 ] The ipr_log_vpd_compact() function triggers a fortified memcpy() warning about a potential string overflow with all versions of clang: In file included from drivers/scsi/ipr.c:43: In file included from include/linux/string.h:254: include/linux/fortify-string.h:520:4: error: call to '__write_overflow_field' declared with 'warning' attribute: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror,-Wattribute-warning] __write_overflow_field(p_size_field, size); ^ include/linux/fortify-string.h:520:4: error: call to '__write_overflow_field' declared with 'warning' attribute: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror,-Wattribute-warning] 2 errors generated. I don't see anything actually wrong with the function, but this is the only instance I can reproduce of the fortification going wrong in the kernel at the moment, so the easiest solution may be to rewrite the function into something that does not trigger the warning. Instead of having a combined buffer for vendor/device/serial strings, use three separate local variables and just truncate the whitespace individually. Link: https://lore.kernel.org/r/20230214132831.2118392-1-arnd@kernel.org Cc: Kees Cook Fixes: 8cf093e275d0 ("[SCSI] ipr: Improved dual adapter errors") Signed-off-by: Arnd Bergmann Reviewed-by: Damien Le Moal Reviewed-by: Kees Cook Acked-by: Brian King Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/ipr.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 2022ffb45041..8c062afb2918 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -1516,23 +1516,22 @@ static void ipr_process_ccn(struct ipr_cmnd *ipr_cmd) } /** - * strip_and_pad_whitespace - Strip and pad trailing whitespace. - * @i: index into buffer - * @buf: string to modify + * strip_whitespace - Strip and pad trailing whitespace. + * @i: size of buffer + * @buf: string to modify * - * This function will strip all trailing whitespace, pad the end - * of the string with a single space, and NULL terminate the string. + * This function will strip all trailing whitespace and + * NUL terminate the string. * - * Return value: - * new length of string **/ -static int strip_and_pad_whitespace(int i, char *buf) +static void strip_whitespace(int i, char *buf) { + if (i < 1) + return; + i--; while (i && buf[i] == ' ') i--; - buf[i+1] = ' '; - buf[i+2] = '\0'; - return i + 2; + buf[i+1] = '\0'; } /** @@ -1547,19 +1546,21 @@ static int strip_and_pad_whitespace(int i, char *buf) static void ipr_log_vpd_compact(char *prefix, struct ipr_hostrcb *hostrcb, struct ipr_vpd *vpd) { - char buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN + IPR_SERIAL_NUM_LEN + 3]; - int i = 0; + char vendor_id[IPR_VENDOR_ID_LEN + 1]; + char product_id[IPR_PROD_ID_LEN + 1]; + char sn[IPR_SERIAL_NUM_LEN + 1]; - memcpy(buffer, vpd->vpids.vendor_id, IPR_VENDOR_ID_LEN); - i = strip_and_pad_whitespace(IPR_VENDOR_ID_LEN - 1, buffer); + memcpy(vendor_id, vpd->vpids.vendor_id, IPR_VENDOR_ID_LEN); + strip_whitespace(IPR_VENDOR_ID_LEN, vendor_id); - memcpy(&buffer[i], vpd->vpids.product_id, IPR_PROD_ID_LEN); - i = strip_and_pad_whitespace(i + IPR_PROD_ID_LEN - 1, buffer); + memcpy(product_id, vpd->vpids.product_id, IPR_PROD_ID_LEN); + strip_whitespace(IPR_PROD_ID_LEN, product_id); - memcpy(&buffer[i], vpd->sn, IPR_SERIAL_NUM_LEN); - buffer[IPR_SERIAL_NUM_LEN + i] = '\0'; + memcpy(sn, vpd->sn, IPR_SERIAL_NUM_LEN); + strip_whitespace(IPR_SERIAL_NUM_LEN, sn); - ipr_hcam_err(hostrcb, "%s VPID/SN: %s\n", prefix, buffer); + ipr_hcam_err(hostrcb, "%s VPID/SN: %s %s %s\n", prefix, + vendor_id, product_id, sn); } /** From abfe73c16b295f2213e9bfc0a1df232056032448 Mon Sep 17 00:00:00 2001 From: Tomas Henzl Date: Mon, 13 Feb 2023 20:37:52 +0100 Subject: [PATCH 099/201] scsi: mpi3mr: Fix an issue found by KASAN [ Upstream commit ae7d45f5283d30274039b95d3e6d53d33c66e991 ] Write only correct size (32 instead of 64 bytes). Link: https://lore.kernel.org/r/20230213193752.6859-1-thenzl@redhat.com Fixes: 42fc9fee116f ("scsi: mpi3mr: Add helper functions to manage device's port") Signed-off-by: Tomas Henzl Acked-by: Sathya Prakash Veerichetty Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/mpi3mr/mpi3mr_transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c index 3fc897336b5e..3b61815979da 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_transport.c +++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c @@ -1280,7 +1280,7 @@ void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc) if (mrioc->sas_hba.enclosure_handle) { if (!(mpi3mr_cfg_get_enclosure_pg0(mrioc, &ioc_status, - &encl_pg0, sizeof(dev_pg0), + &encl_pg0, sizeof(encl_pg0), MPI3_ENCLOS_PGAD_FORM_HANDLE, mrioc->sas_hba.enclosure_handle)) && (ioc_status == MPI3_IOCSTATUS_SUCCESS)) From 6a675a6d57d31da43d8da576465c1cd5d5b0bd3d Mon Sep 17 00:00:00 2001 From: Shin'ichiro Kawasaki Date: Tue, 14 Feb 2023 09:50:18 +0900 Subject: [PATCH 100/201] scsi: mpi3mr: Use number of bits to manage bitmap sizes [ Upstream commit 339e61565f81a6534afdc18fd854b2e2628bf5db ] To allocate bitmaps, the mpi3mr driver calculates sizes of bitmaps using byte as unit. However, bitmap helper functions assume that bitmaps are allocated using unsigned long as unit. This gap causes memory access beyond the bitmap sizes and results in "BUG: KASAN: slab-out-of-bounds". The BUG was observed at firmware download to eHBA-9600. Call trace indicated that the out-of-bounds access happened in find_first_zero_bit() called from mpi3mr_send_event_ack() for miroc->evtack_cmds_bitmap. To fix the BUG, do not use bytes to manage bitmap sizes. Instead, use number of bits, and call bitmap helper functions which take number of bits as arguments. For memory allocation, call bitmap_zalloc() instead of kzalloc() and krealloc(). For memory free, call bitmap_free() instead of kfree(). For zero clear, call bitmap_clear() instead of memset(). Remove three fields for bitmap byte sizes in struct scmd_priv which are no longer required. Replace the field dev_handle_bitmap_sz with dev_handle_bitmap_bits to keep number of bits of removepend_bitmap across resize. Link: https://lore.kernel.org/r/20230214005019.1897251-4-shinichiro.kawasaki@wdc.com Fixes: c5758fc72b92 ("scsi: mpi3mr: Gracefully handle online FW update operation") Fixes: e844adb1fbdc ("scsi: mpi3mr: Implement SCSI error handler hooks") Fixes: c1af985d27da ("scsi: mpi3mr: Add Event acknowledgment logic") Fixes: 824a156633df ("scsi: mpi3mr: Base driver code") Signed-off-by: Shin'ichiro Kawasaki Acked-by: Sathya Prakash Veerichetty Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/mpi3mr/mpi3mr.h | 10 +---- drivers/scsi/mpi3mr/mpi3mr_fw.c | 75 ++++++++++++++------------------- 2 files changed, 33 insertions(+), 52 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index def4c5e15cd8..8a438f248a82 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -955,19 +955,16 @@ struct scmd_priv { * @chain_buf_count: Chain buffer count * @chain_buf_pool: Chain buffer pool * @chain_sgl_list: Chain SGL list - * @chain_bitmap_sz: Chain buffer allocator bitmap size * @chain_bitmap: Chain buffer allocator bitmap * @chain_buf_lock: Chain buffer list lock * @bsg_cmds: Command tracker for BSG command * @host_tm_cmds: Command tracker for task management commands * @dev_rmhs_cmds: Command tracker for device removal commands * @evtack_cmds: Command tracker for event ack commands - * @devrem_bitmap_sz: Device removal bitmap size * @devrem_bitmap: Device removal bitmap - * @dev_handle_bitmap_sz: Device handle bitmap size + * @dev_handle_bitmap_bits: Number of bits in device handle bitmap * @removepend_bitmap: Remove pending bitmap * @delayed_rmhs_list: Delayed device removal list - * @evtack_cmds_bitmap_sz: Event Ack bitmap size * @evtack_cmds_bitmap: Event Ack bitmap * @delayed_evtack_cmds_list: Delayed event acknowledgment list * @ts_update_counter: Timestamp update counter @@ -1128,7 +1125,6 @@ struct mpi3mr_ioc { u32 chain_buf_count; struct dma_pool *chain_buf_pool; struct chain_element *chain_sgl_list; - u16 chain_bitmap_sz; void *chain_bitmap; spinlock_t chain_buf_lock; @@ -1136,12 +1132,10 @@ struct mpi3mr_ioc { struct mpi3mr_drv_cmd host_tm_cmds; struct mpi3mr_drv_cmd dev_rmhs_cmds[MPI3MR_NUM_DEVRMCMD]; struct mpi3mr_drv_cmd evtack_cmds[MPI3MR_NUM_EVTACKCMD]; - u16 devrem_bitmap_sz; void *devrem_bitmap; - u16 dev_handle_bitmap_sz; + u16 dev_handle_bitmap_bits; void *removepend_bitmap; struct list_head delayed_rmhs_list; - u16 evtack_cmds_bitmap_sz; void *evtack_cmds_bitmap; struct list_head delayed_evtack_cmds_list; diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 0c4aabaefdcc..1e4467ea8472 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -1128,7 +1128,6 @@ static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc, static int mpi3mr_revalidate_factsdata(struct mpi3mr_ioc *mrioc) { - u16 dev_handle_bitmap_sz; void *removepend_bitmap; if (mrioc->facts.reply_sz > mrioc->reply_sz) { @@ -1160,25 +1159,23 @@ mpi3mr_revalidate_factsdata(struct mpi3mr_ioc *mrioc) "\tcontroller while sas transport support is enabled at the\n" "\tdriver, please reboot the system or reload the driver\n"); - dev_handle_bitmap_sz = mrioc->facts.max_devhandle / 8; - if (mrioc->facts.max_devhandle % 8) - dev_handle_bitmap_sz++; - if (dev_handle_bitmap_sz > mrioc->dev_handle_bitmap_sz) { - removepend_bitmap = krealloc(mrioc->removepend_bitmap, - dev_handle_bitmap_sz, GFP_KERNEL); + if (mrioc->facts.max_devhandle > mrioc->dev_handle_bitmap_bits) { + removepend_bitmap = bitmap_zalloc(mrioc->facts.max_devhandle, + GFP_KERNEL); if (!removepend_bitmap) { ioc_err(mrioc, - "failed to increase removepend_bitmap sz from: %d to %d\n", - mrioc->dev_handle_bitmap_sz, dev_handle_bitmap_sz); + "failed to increase removepend_bitmap bits from %d to %d\n", + mrioc->dev_handle_bitmap_bits, + mrioc->facts.max_devhandle); return -EPERM; } - memset(removepend_bitmap + mrioc->dev_handle_bitmap_sz, 0, - dev_handle_bitmap_sz - mrioc->dev_handle_bitmap_sz); + bitmap_free(mrioc->removepend_bitmap); mrioc->removepend_bitmap = removepend_bitmap; ioc_info(mrioc, - "increased dev_handle_bitmap_sz from %d to %d\n", - mrioc->dev_handle_bitmap_sz, dev_handle_bitmap_sz); - mrioc->dev_handle_bitmap_sz = dev_handle_bitmap_sz; + "increased bits of dev_handle_bitmap from %d to %d\n", + mrioc->dev_handle_bitmap_bits, + mrioc->facts.max_devhandle); + mrioc->dev_handle_bitmap_bits = mrioc->facts.max_devhandle; } return 0; @@ -2957,27 +2954,18 @@ static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc) if (!mrioc->pel_abort_cmd.reply) goto out_failed; - mrioc->dev_handle_bitmap_sz = mrioc->facts.max_devhandle / 8; - if (mrioc->facts.max_devhandle % 8) - mrioc->dev_handle_bitmap_sz++; - mrioc->removepend_bitmap = kzalloc(mrioc->dev_handle_bitmap_sz, - GFP_KERNEL); + mrioc->dev_handle_bitmap_bits = mrioc->facts.max_devhandle; + mrioc->removepend_bitmap = bitmap_zalloc(mrioc->dev_handle_bitmap_bits, + GFP_KERNEL); if (!mrioc->removepend_bitmap) goto out_failed; - mrioc->devrem_bitmap_sz = MPI3MR_NUM_DEVRMCMD / 8; - if (MPI3MR_NUM_DEVRMCMD % 8) - mrioc->devrem_bitmap_sz++; - mrioc->devrem_bitmap = kzalloc(mrioc->devrem_bitmap_sz, - GFP_KERNEL); + mrioc->devrem_bitmap = bitmap_zalloc(MPI3MR_NUM_DEVRMCMD, GFP_KERNEL); if (!mrioc->devrem_bitmap) goto out_failed; - mrioc->evtack_cmds_bitmap_sz = MPI3MR_NUM_EVTACKCMD / 8; - if (MPI3MR_NUM_EVTACKCMD % 8) - mrioc->evtack_cmds_bitmap_sz++; - mrioc->evtack_cmds_bitmap = kzalloc(mrioc->evtack_cmds_bitmap_sz, - GFP_KERNEL); + mrioc->evtack_cmds_bitmap = bitmap_zalloc(MPI3MR_NUM_EVTACKCMD, + GFP_KERNEL); if (!mrioc->evtack_cmds_bitmap) goto out_failed; @@ -3415,10 +3403,7 @@ static int mpi3mr_alloc_chain_bufs(struct mpi3mr_ioc *mrioc) if (!mrioc->chain_sgl_list[i].addr) goto out_failed; } - mrioc->chain_bitmap_sz = num_chains / 8; - if (num_chains % 8) - mrioc->chain_bitmap_sz++; - mrioc->chain_bitmap = kzalloc(mrioc->chain_bitmap_sz, GFP_KERNEL); + mrioc->chain_bitmap = bitmap_zalloc(num_chains, GFP_KERNEL); if (!mrioc->chain_bitmap) goto out_failed; return retval; @@ -4190,10 +4175,11 @@ void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc) for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) memset(mrioc->evtack_cmds[i].reply, 0, sizeof(*mrioc->evtack_cmds[i].reply)); - memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz); - memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz); - memset(mrioc->evtack_cmds_bitmap, 0, - mrioc->evtack_cmds_bitmap_sz); + bitmap_clear(mrioc->removepend_bitmap, 0, + mrioc->dev_handle_bitmap_bits); + bitmap_clear(mrioc->devrem_bitmap, 0, MPI3MR_NUM_DEVRMCMD); + bitmap_clear(mrioc->evtack_cmds_bitmap, 0, + MPI3MR_NUM_EVTACKCMD); } for (i = 0; i < mrioc->num_queues; i++) { @@ -4319,16 +4305,16 @@ void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc) mrioc->evtack_cmds[i].reply = NULL; } - kfree(mrioc->removepend_bitmap); + bitmap_free(mrioc->removepend_bitmap); mrioc->removepend_bitmap = NULL; - kfree(mrioc->devrem_bitmap); + bitmap_free(mrioc->devrem_bitmap); mrioc->devrem_bitmap = NULL; - kfree(mrioc->evtack_cmds_bitmap); + bitmap_free(mrioc->evtack_cmds_bitmap); mrioc->evtack_cmds_bitmap = NULL; - kfree(mrioc->chain_bitmap); + bitmap_free(mrioc->chain_bitmap); mrioc->chain_bitmap = NULL; kfree(mrioc->transport_cmds.reply); @@ -4887,9 +4873,10 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, mpi3mr_flush_delayed_cmd_lists(mrioc); mpi3mr_flush_drv_cmds(mrioc); - memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz); - memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz); - memset(mrioc->evtack_cmds_bitmap, 0, mrioc->evtack_cmds_bitmap_sz); + bitmap_clear(mrioc->devrem_bitmap, 0, MPI3MR_NUM_DEVRMCMD); + bitmap_clear(mrioc->removepend_bitmap, 0, + mrioc->dev_handle_bitmap_bits); + bitmap_clear(mrioc->evtack_cmds_bitmap, 0, MPI3MR_NUM_EVTACKCMD); mpi3mr_flush_host_io(mrioc); mpi3mr_cleanup_fwevt_list(mrioc); mpi3mr_invalidate_devhandles(mrioc); From 1e276e8acb8e24bce493603d19a699f76a1583fa Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 14 Feb 2023 23:27:53 +0100 Subject: [PATCH 101/201] rtc: allow rtc_read_alarm without read_alarm callback [ Upstream commit a783c962619271a8b905efad1d89adfec11ae0c8 ] .read_alarm is not necessary to read the current alarm because it is recorded in the aie_timer and so rtc_read_alarm() will never call rtc_read_alarm_internal() which is the only function calling the callback. Reported-by: Zhipeng Wang Reported-by: Marcel Ziswiler Fixes: 7ae41220ef58 ("rtc: introduce features bitfield") Tested-by: Philippe Schenker Link: https://lore.kernel.org/r/20230214222754.582582-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin --- drivers/rtc/interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 9edd662c69ac..3d0fbc644f57 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -392,7 +392,7 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) return err; if (!rtc->ops) { err = -ENODEV; - } else if (!test_bit(RTC_FEATURE_ALARM, rtc->features) || !rtc->ops->read_alarm) { + } else if (!test_bit(RTC_FEATURE_ALARM, rtc->features)) { err = -EINVAL; } else { memset(alarm, 0, sizeof(struct rtc_wkalrm)); From b0498e95cae75615540d29682f830da1c190e0a9 Mon Sep 17 00:00:00 2001 From: Wojciech Lukowicz Date: Sat, 18 Feb 2023 18:41:41 +0000 Subject: [PATCH 102/201] io_uring: fix size calculation when registering buf ring [ Upstream commit 48ba08374e779421ca34bd14b4834aae19fc3e6a ] Using struct_size() to calculate the size of io_uring_buf_ring will sum the size of the struct and of the bufs array. However, the struct's fields are overlaid with the array making the calculated size larger than it should be. When registering a ring with N * PAGE_SIZE / sizeof(struct io_uring_buf) entries, i.e. with fully filled pages, the calculated size will span one more page than it should and io_uring will try to pin the following page. Depending on how the application allocated the ring, it might succeed using an unrelated page or fail returning EFAULT. The size of the ring should be the product of ring_entries and the size of io_uring_buf, i.e. the size of the bufs array only. Fixes: c7fb19428d67 ("io_uring: add support for ring mapped supplied buffers") Signed-off-by: Wojciech Lukowicz Reviewed-by: Gabriel Krisman Bertazi Link: https://lore.kernel.org/r/20230218184141.70891-1-wlukowicz01@gmail.com Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- io_uring/kbuf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/io_uring/kbuf.c b/io_uring/kbuf.c index e2c46889d5fa..746b137b96e9 100644 --- a/io_uring/kbuf.c +++ b/io_uring/kbuf.c @@ -509,7 +509,7 @@ int io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg) } pages = io_pin_pages(reg.ring_addr, - struct_size(br, bufs, reg.ring_entries), + flex_array_size(br, bufs, reg.ring_entries), &nr_pages); if (IS_ERR(pages)) { kfree(free_bl); From 4be26d553a3f1d4f54f25353d1496c562002126d Mon Sep 17 00:00:00 2001 From: Zhong Jinghua Date: Tue, 21 Feb 2023 17:50:27 +0800 Subject: [PATCH 103/201] loop: loop_set_status_from_info() check before assignment [ Upstream commit 9f6ad5d533d1c71e51bdd06a5712c4fbc8768dfa ] In loop_set_status_from_info(), lo->lo_offset and lo->lo_sizelimit should be checked before reassignment, because if an overflow error occurs, the original correct value will be changed to the wrong value, and it will not be changed back. More, the original patch did not solve the problem, the value was set and ioctl returned an error, but the subsequent io used the value in the loop driver, which still caused an alarm: loop_handle_cmd do_req_filebacked loff_t pos = ((loff_t) blk_rq_pos(rq) << 9) + lo->lo_offset; lo_rw_aio cmd->iocb.ki_pos = pos Fixes: c490a0b5a4f3 ("loop: Check for overflow while configuring loop") Signed-off-by: Zhong Jinghua Reviewed-by: Chaitanya Kulkarni Link: https://lore.kernel.org/r/20230221095027.3656193-1-zhongjinghua@huaweicloud.com Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- drivers/block/loop.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index df628e30bca4..981464e561df 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -977,13 +977,13 @@ loop_set_status_from_info(struct loop_device *lo, return -EINVAL; } + /* Avoid assigning overflow values */ + if (info->lo_offset > LLONG_MAX || info->lo_sizelimit > LLONG_MAX) + return -EOVERFLOW; + lo->lo_offset = info->lo_offset; lo->lo_sizelimit = info->lo_sizelimit; - /* loff_t vars have been assigned __u64 */ - if (lo->lo_offset < 0 || lo->lo_sizelimit < 0) - return -EOVERFLOW; - memcpy(lo->lo_file_name, info->lo_file_name, LO_NAME_SIZE); lo->lo_file_name[LO_NAME_SIZE-1] = 0; lo->lo_flags = info->lo_flags; From f558edac8f6cf711db59d8752284407dc91e4be6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Fri, 24 Feb 2023 11:45:51 +0100 Subject: [PATCH 104/201] ASoC: adau7118: don't disable regulators on device unbind MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit b5bfa7277ee7d944421e0ef193586c6e34d7492c ] The regulators are supposed to be controlled through the set_bias_level() component callback. Moreover, the regulators are not enabled during probe and so, this would lead to a regulator unbalanced use count. Fixes: ca514c0f12b02 ("ASOC: Add ADAU7118 8 Channel PDM-to-I2S/TDM Converter driver") Signed-off-by: Nuno Sá Link: https://lore.kernel.org/r/20230224104551.1139981-1-nuno.sa@analog.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/codecs/adau7118.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/sound/soc/codecs/adau7118.c b/sound/soc/codecs/adau7118.c index bbb097249887..a663d37e5776 100644 --- a/sound/soc/codecs/adau7118.c +++ b/sound/soc/codecs/adau7118.c @@ -444,22 +444,6 @@ static const struct snd_soc_component_driver adau7118_component_driver = { .endianness = 1, }; -static void adau7118_regulator_disable(void *data) -{ - struct adau7118_data *st = data; - int ret; - /* - * If we fail to disable DVDD, don't bother in trying IOVDD. We - * actually don't want to be left in the situation where DVDD - * is enabled and IOVDD is disabled. - */ - ret = regulator_disable(st->dvdd); - if (ret) - return; - - regulator_disable(st->iovdd); -} - static int adau7118_regulator_setup(struct adau7118_data *st) { st->iovdd = devm_regulator_get(st->dev, "iovdd"); @@ -481,8 +465,7 @@ static int adau7118_regulator_setup(struct adau7118_data *st) regcache_cache_only(st->map, true); } - return devm_add_action_or_reset(st->dev, adau7118_regulator_disable, - st); + return 0; } static int adau7118_parset_dt(const struct adau7118_data *st) From c664c38355196f37ae00e61a15179c78f16b909f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Fri, 24 Feb 2023 16:33:00 +0100 Subject: [PATCH 105/201] ASoC: apple: mca: Fix final status read on SERDES reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit aaf5f0d76b6e1870e3674408de2b13a92a4d4059 ] From within the early trigger we are doing a reset of the SERDES unit, but the final status read is on a bad address. Add the missing SERDES unit offset in calculation of the address. Fixes: 3df5d0d97289 ("ASoC: apple: mca: Start new platform driver") Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20230224153302.45365-1-povik+lin@cutebit.org Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/apple/mca.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c index 24381c42eb54..9cceeb259952 100644 --- a/sound/soc/apple/mca.c +++ b/sound/soc/apple/mca.c @@ -210,7 +210,7 @@ static void mca_fe_early_trigger(struct snd_pcm_substream *substream, int cmd, SERDES_CONF_SOME_RST); readl_relaxed(cl->base + serdes_conf); mca_modify(cl, serdes_conf, SERDES_STATUS_RST, 0); - WARN_ON(readl_relaxed(cl->base + REG_SERDES_STATUS) & + WARN_ON(readl_relaxed(cl->base + serdes_unit + REG_SERDES_STATUS) & SERDES_STATUS_RST); break; default: From 0c398c1c19ff562570f0c789aa8d7c6283078fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Fri, 24 Feb 2023 16:33:01 +0100 Subject: [PATCH 106/201] ASoC: apple: mca: Fix SERDES reset sequence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit d8b3e396088d787771f19fd3b7949e080dc31d6f ] Fix the reset sequence of reads and writes that we invoke from within the early trigger. It looks like there never was a SERDES_CONF_SOME_RST bit that should be involved in the reset sequence, and its presence in the driver code is a mistake from earlier. Instead, the reset sequence should go as follows: We should switch the the SERDES unit's SYNC_SEL mux to the value of 7 (so outside the range of 1...6 representing cluster's SYNCGEN units), then raise the RST bit in SERDES_STATUS and wait for it to clear. Properly resetting the SERDES unit fixes frame desynchronization hazard in case of long frames (longer than 4 used slots). The desynchronization manifests itself by rotating the PCM channels. Fixes: 3df5d0d97289 ("ASoC: apple: mca: Start new platform driver") Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20230224153302.45365-2-povik+lin@cutebit.org Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/apple/mca.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c index 9cceeb259952..aea08c7b2ee8 100644 --- a/sound/soc/apple/mca.c +++ b/sound/soc/apple/mca.c @@ -101,7 +101,6 @@ #define SERDES_CONF_UNK3 BIT(14) #define SERDES_CONF_NO_DATA_FEEDBACK BIT(15) #define SERDES_CONF_SYNC_SEL GENMASK(18, 16) -#define SERDES_CONF_SOME_RST BIT(19) #define REG_TX_SERDES_BITSTART 0x08 #define REG_RX_SERDES_BITSTART 0x0c #define REG_TX_SERDES_SLOTMASK 0x0c @@ -203,15 +202,24 @@ static void mca_fe_early_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL, + FIELD_PREP(SERDES_CONF_SYNC_SEL, 0)); + mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL, + FIELD_PREP(SERDES_CONF_SYNC_SEL, 7)); mca_modify(cl, serdes_unit + REG_SERDES_STATUS, SERDES_STATUS_EN | SERDES_STATUS_RST, SERDES_STATUS_RST); - mca_modify(cl, serdes_conf, SERDES_CONF_SOME_RST, - SERDES_CONF_SOME_RST); - readl_relaxed(cl->base + serdes_conf); - mca_modify(cl, serdes_conf, SERDES_STATUS_RST, 0); + /* + * Experiments suggest that it takes at most ~1 us + * for the bit to clear, so wait 2 us for good measure. + */ + udelay(2); WARN_ON(readl_relaxed(cl->base + serdes_unit + REG_SERDES_STATUS) & SERDES_STATUS_RST); + mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL, + FIELD_PREP(SERDES_CONF_SYNC_SEL, 0)); + mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL, + FIELD_PREP(SERDES_CONF_SYNC_SEL, cl->no + 1)); break; default: break; From 124fee6c62b21c8fa6216f930291a9d5f2e210b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Fri, 24 Feb 2023 16:33:02 +0100 Subject: [PATCH 107/201] ASoC: apple: mca: Improve handling of unavailable DMA channels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit fb1847cc460c127b12720119eae5f438ffc62e85 ] When we fail to obtain a DMA channel, don't return a blanket -EINVAL, instead return the original error code if there's one. This makes deferring work as it should. Also don't print an error message for -EPROBE_DEFER. Fixes: 4ec8179c212f ("ASoC: apple: mca: Postpone requesting of DMA channels") Signed-off-by: Martin Povišer Link: https://lore.kernel.org/r/20230224153302.45365-3-povik+lin@cutebit.org Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/apple/mca.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c index aea08c7b2ee8..64750db9b963 100644 --- a/sound/soc/apple/mca.c +++ b/sound/soc/apple/mca.c @@ -950,10 +950,17 @@ static int mca_pcm_new(struct snd_soc_component *component, chan = mca_request_dma_channel(cl, i); if (IS_ERR_OR_NULL(chan)) { + mca_pcm_free(component, rtd->pcm); + + if (chan && PTR_ERR(chan) == -EPROBE_DEFER) + return PTR_ERR(chan); + dev_err(component->dev, "unable to obtain DMA channel (stream %d cluster %d): %pe\n", i, cl->no, chan); - mca_pcm_free(component, rtd->pcm); - return -EINVAL; + + if (!chan) + return -EINVAL; + return PTR_ERR(chan); } cl->dma_chans[i] = chan; From 117dc3f6b64150e8a10c5037b0d0b3556233980b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 21 Feb 2023 14:02:25 -0800 Subject: [PATCH 108/201] nvme: bring back auto-removal of deleted namespaces during sequential scan [ Upstream commit 0dd6fff2aad4e35633fef1ea72838bec5b47559a ] Bring back the check of the Identify Namespace return value for the legacy NVMe 1.0-style sequential scanning. While NVMe 1.0 does not support namespace management, there are "modern" cloud solutions like Google Cloud Platform that claim the obsolete 1.0 compliance for no good reason while supporting proprietary sideband namespace management. Fixes: 1a893c2bfef4 ("nvme: refactor namespace probing") Reported-by: Nils Hanke Signed-off-by: Christoph Hellwig Reviewed-by: Keith Busch Reviewed-by: Sagi Grimberg Tested-by: Nils Hanke Signed-off-by: Sasha Levin --- drivers/nvme/host/core.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 5acc9ae225df..2031fd960549 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -38,6 +38,7 @@ struct nvme_ns_info { bool is_shared; bool is_readonly; bool is_ready; + bool is_removed; }; unsigned int admin_timeout = 60; @@ -1439,16 +1440,8 @@ static int nvme_identify_ns(struct nvme_ctrl *ctrl, unsigned nsid, error = nvme_submit_sync_cmd(ctrl->admin_q, &c, *id, sizeof(**id)); if (error) { dev_warn(ctrl->device, "Identify namespace failed (%d)\n", error); - goto out_free_id; + kfree(*id); } - - error = NVME_SC_INVALID_NS | NVME_SC_DNR; - if ((*id)->ncap == 0) /* namespace not allocated or attached */ - goto out_free_id; - return 0; - -out_free_id: - kfree(*id); return error; } @@ -1462,6 +1455,13 @@ static int nvme_ns_info_from_identify(struct nvme_ctrl *ctrl, ret = nvme_identify_ns(ctrl, info->nsid, &id); if (ret) return ret; + + if (id->ncap == 0) { + /* namespace not allocated or attached */ + info->is_removed = true; + return -ENODEV; + } + info->anagrpid = id->anagrpid; info->is_shared = id->nmic & NVME_NS_NMIC_SHARED; info->is_readonly = id->nsattr & NVME_NS_ATTR_RO; @@ -4388,6 +4388,7 @@ static void nvme_scan_ns(struct nvme_ctrl *ctrl, unsigned nsid) { struct nvme_ns_info info = { .nsid = nsid }; struct nvme_ns *ns; + int ret; if (nvme_identify_ns_descs(ctrl, &info)) return; @@ -4404,19 +4405,19 @@ static void nvme_scan_ns(struct nvme_ctrl *ctrl, unsigned nsid) * set up a namespace. If not fall back to the legacy version. */ if ((ctrl->cap & NVME_CAP_CRMS_CRIMS) || - (info.ids.csi != NVME_CSI_NVM && info.ids.csi != NVME_CSI_ZNS)) { - if (nvme_ns_info_from_id_cs_indep(ctrl, &info)) - return; - } else { - if (nvme_ns_info_from_identify(ctrl, &info)) - return; - } + (info.ids.csi != NVME_CSI_NVM && info.ids.csi != NVME_CSI_ZNS)) + ret = nvme_ns_info_from_id_cs_indep(ctrl, &info); + else + ret = nvme_ns_info_from_identify(ctrl, &info); + + if (info.is_removed) + nvme_ns_remove_by_nsid(ctrl, nsid); /* * Ignore the namespace if it is not ready. We will get an AEN once it * becomes ready and restart the scan. */ - if (!info.is_ready) + if (ret || !info.is_ready) return; ns = nvme_find_get_ns(ctrl, nsid); From fe2d9e54165dadaa0d0cc3355c0be9c3e129fa0d Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 26 Feb 2023 21:42:54 +0900 Subject: [PATCH 109/201] nvme-tcp: don't access released socket during error recovery [ Upstream commit 76d54bf20cdcc1ed7569a89885e09636e9a8d71d ] While the error recovery work is temporarily failing reconnect attempts, running the 'nvme list' command causes a kernel NULL pointer dereference by calling getsockname() with a released socket. During error recovery work, the nvme tcp socket is released and a new one created, so it is not safe to access the socket without proper check. Signed-off-by: Akinobu Mita Fixes: 02c57a82c008 ("nvme-tcp: print actual source IP address through sysfs "address" attr") Reviewed-by: Martin Belanger Reviewed-by: Hannes Reinecke Signed-off-by: Christoph Hellwig Signed-off-by: Sasha Levin --- drivers/nvme/host/tcp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 1dc7c733c7e3..bb80192c16b6 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -2488,6 +2488,10 @@ static int nvme_tcp_get_address(struct nvme_ctrl *ctrl, char *buf, int size) len = nvmf_get_address(ctrl, buf, size); + mutex_lock(&queue->queue_lock); + + if (!test_bit(NVME_TCP_Q_LIVE, &queue->flags)) + goto done; ret = kernel_getsockname(queue->sock, (struct sockaddr *)&src_addr); if (ret > 0) { if (len > 0) @@ -2495,6 +2499,8 @@ static int nvme_tcp_get_address(struct nvme_ctrl *ctrl, char *buf, int size) len += scnprintf(buf + len, size - len, "%ssrc_addr=%pISc\n", (len) ? "," : "", &src_addr); } +done: + mutex_unlock(&queue->queue_lock); return len; } From daf8c1062d139679f296d130825a0cde1baeb2a2 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Tue, 21 Feb 2023 17:51:06 +0100 Subject: [PATCH 110/201] nvme-fabrics: show well known discovery name [ Upstream commit 26a57cb35548ae67c14871cccbf50da3edb01ea4 ] The kernel always logs the unique subsystem name for a discovery controller, even in the case user space asked for the well known. This has lead to confusion as the logs of nvme-cli and the kernel logs didn't match. First, nvme-cli connects to the well known discovery controller to figure out if it supports TP8013. If so then nvme-cli disconnects and connects to the unique discovery controller. Currently, the kernel show that user space connected twice to the unique one. To avoid further confusion, show the well known discovery controller if user space asked for it: $ nvme connect-all -v -t tcp -a 192.168.0.1 nvme0: nqn.2014-08.org.nvmexpress.discovery connected nvme0: nqn.2014-08.org.nvmexpress.discovery disconnected nvme0: nqn.discovery connected kernel log: nvme nvme0: new ctrl: NQN "nqn.2014-08.org.nvmexpress.discovery", addr 192.168.0.1:8009 nvme nvme0: Removing ctrl: NQN "nqn.2014-08.org.nvmexpress.discovery" nvme nvme0: new ctrl: NQN "nqn.discovery", addr 192.168.0.1:8009 Fixes: e5ea42faa773 ("nvme: display correct subsystem NQN") Signed-off-by: Daniel Wagner Reviewed-by: Hannes Reinecke Signed-off-by: Christoph Hellwig Signed-off-by: Sasha Levin --- drivers/nvme/host/fabrics.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/nvme/host/fabrics.h b/drivers/nvme/host/fabrics.h index a6e22116e139..dcac3df8a5f7 100644 --- a/drivers/nvme/host/fabrics.h +++ b/drivers/nvme/host/fabrics.h @@ -189,7 +189,8 @@ nvmf_ctlr_matches_baseopts(struct nvme_ctrl *ctrl, static inline char *nvmf_ctrl_subsysnqn(struct nvme_ctrl *ctrl) { - if (!ctrl->subsys) + if (!ctrl->subsys || + !strcmp(ctrl->opts->subsysnqn, NVME_DISC_SUBSYS_NAME)) return ctrl->opts->subsysnqn; return ctrl->subsys->subnqn; } From bb12470672e70dc2900147f9142a0821b3e45f83 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 27 Feb 2023 09:58:26 +0100 Subject: [PATCH 111/201] ASoC: zl38060 add gpiolib dependency [ Upstream commit 0de2cc3707b6b6e2ad40bd24ce09a5c1f65d01e1 ] Without gpiolib, this driver fails to link: arm-linux-gnueabi-ld: sound/soc/codecs/zl38060.o: in function `chip_gpio_get': zl38060.c:(.text+0x30): undefined reference to `gpiochip_get_data' arm-linux-gnueabi-ld: sound/soc/codecs/zl38060.o: in function `zl38_spi_probe': zl38060.c:(.text+0xa18): undefined reference to `devm_gpiochip_add_data_with_key' This appears to have been in the driver since the start, but is hard to hit in randconfig testing since gpiolib is almost always selected by something else. Fixes: 52e8a94baf90 ("ASoC: Add initial ZL38060 driver") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20230227085850.2503725-1-arnd@kernel.org Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 7022e6286e6c..3f16ad1c3758 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -2039,6 +2039,7 @@ config SND_SOC_WSA883X config SND_SOC_ZL38060 tristate "Microsemi ZL38060 Connected Home Audio Processor" depends on SPI_MASTER + depends on GPIOLIB select REGMAP help Support for ZL38060 Connected Home Audio Processor from Microsemi, From ada41093fb1b6cdc0bed7cd02bbf1b42a3f9a4fc Mon Sep 17 00:00:00 2001 From: Trevor Wu Date: Wed, 1 Mar 2023 19:02:00 +0800 Subject: [PATCH 112/201] ASoC: mediatek: mt8195: add missing initialization [ Upstream commit b56ec2992a2e43bc3e60d6db86849d31640e791f ] In etdm dai driver, dai_etdm_parse_of() function is used to parse dts properties to get parameters. There are two for-loops which are sepearately for all etdm and etdm input only cases. In etdm in only loop, dai_id is not initialized, so it keeps the value intiliazed in another loop. In the patch, add the missing initialization to fix the unexpected parsing problem. Fixes: 1de9a54acafb ("ASoC: mediatek: mt8195: support etdm in platform driver") Signed-off-by: Trevor Wu Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20230301110200.26177-3-trevor.wu@mediatek.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/mediatek/mt8195/mt8195-dai-etdm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c index c2e268054773..f2c9a1fdbe0d 100644 --- a/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c +++ b/sound/soc/mediatek/mt8195/mt8195-dai-etdm.c @@ -2567,6 +2567,9 @@ static void mt8195_dai_etdm_parse_of(struct mtk_base_afe *afe) /* etdm in only */ for (i = 0; i < 2; i++) { + dai_id = ETDM_TO_DAI_ID(i); + etdm_data = afe_priv->dai_priv[dai_id]; + ret = snprintf(prop, sizeof(prop), "mediatek,%s-chn-disabled", of_afe_etdms[i].name); From 69e49f1b53605706bc2203455021539aba2ebe21 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 27 Feb 2023 13:06:50 +0300 Subject: [PATCH 113/201] thermal: intel: quark_dts: fix error pointer dereference [ Upstream commit f1b930e740811d416de4d2074da48b6633a672c8 ] If alloc_soc_dts() fails, then we can just return. Trying to free "soc_dts" will lead to an Oops. Fixes: 8c1876939663 ("thermal: intel Quark SoC X1000 DTS thermal driver") Signed-off-by: Dan Carpenter Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin --- drivers/thermal/intel/intel_quark_dts_thermal.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/thermal/intel/intel_quark_dts_thermal.c b/drivers/thermal/intel/intel_quark_dts_thermal.c index 3eafc6b0e6c3..b43fbd5eaa6b 100644 --- a/drivers/thermal/intel/intel_quark_dts_thermal.c +++ b/drivers/thermal/intel/intel_quark_dts_thermal.c @@ -415,22 +415,14 @@ MODULE_DEVICE_TABLE(x86cpu, qrk_thermal_ids); static int __init intel_quark_thermal_init(void) { - int err = 0; - if (!x86_match_cpu(qrk_thermal_ids) || !iosf_mbi_available()) return -ENODEV; soc_dts = alloc_soc_dts(); - if (IS_ERR(soc_dts)) { - err = PTR_ERR(soc_dts); - goto err_free; - } + if (IS_ERR(soc_dts)) + return PTR_ERR(soc_dts); return 0; - -err_free: - free_soc_dts(soc_dts); - return err; } static void __exit intel_quark_thermal_exit(void) From 92271fc1cc5da8433bc91e8c12d2261fd9204273 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 25 Feb 2023 21:39:52 -0800 Subject: [PATCH 114/201] thermal: intel: BXT_PMIC: select REGMAP instead of depending on it [ Upstream commit 1467fb960349dfa5e300658f1a409dde2cfb0c51 ] REGMAP is a hidden (not user visible) symbol. Users cannot set it directly thru "make *config", so drivers should select it instead of depending on it if they need it. Consistently using "select" or "depends on" can also help reduce Kconfig circular dependency issues. Therefore, change the use of "depends on REGMAP" to "select REGMAP". Fixes: b474303ffd57 ("thermal: add Intel BXT WhiskeyCove PMIC thermal driver") Signed-off-by: Randy Dunlap Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin --- drivers/thermal/intel/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/thermal/intel/Kconfig b/drivers/thermal/intel/Kconfig index f0c845679250..e3cfad10d5dd 100644 --- a/drivers/thermal/intel/Kconfig +++ b/drivers/thermal/intel/Kconfig @@ -64,7 +64,8 @@ endmenu config INTEL_BXT_PMIC_THERMAL tristate "Intel Broxton PMIC thermal driver" - depends on X86 && INTEL_SOC_PMIC_BXTWC && REGMAP + depends on X86 && INTEL_SOC_PMIC_BXTWC + select REGMAP help Select this driver for Intel Broxton PMIC with ADC channels monitoring system temperature measurements and alerts. From 2072332c04dff0a3e29cf8c8586c6a0533110317 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Fri, 13 Jan 2023 20:55:01 +0800 Subject: [PATCH 115/201] tracing: Add NULL checks for buffer in ring_buffer_free_read_page() [ Upstream commit 3e4272b9954094907f16861199728f14002fcaf6 ] In a previous commit 7433632c9ff6, buffer, buffer->buffers and buffer->buffers[cpu] in ring_buffer_wake_waiters() can be NULL, and thus the related checks are added. However, in the same call stack, these variables are also used in ring_buffer_free_read_page(): tracing_buffers_release() ring_buffer_wake_waiters(iter->array_buffer->buffer) cpu_buffer = buffer->buffers[cpu] -> Add checks by previous commit ring_buffer_free_read_page(iter->array_buffer->buffer) cpu_buffer = buffer->buffers[cpu] -> No check Thus, to avod possible null-pointer derefernces, the related checks should be added. These results are reported by a static tool designed by myself. Link: https://lkml.kernel.org/r/20230113125501.760324-1-baijiaju1990@gmail.com Reported-by: TOTE Robot Signed-off-by: Jia-Ju Bai Signed-off-by: Steven Rostedt (Google) Signed-off-by: Sasha Levin --- kernel/trace/ring_buffer.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index c35e08b74014..361bd8beafdf 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -5588,11 +5588,16 @@ EXPORT_SYMBOL_GPL(ring_buffer_alloc_read_page); */ void ring_buffer_free_read_page(struct trace_buffer *buffer, int cpu, void *data) { - struct ring_buffer_per_cpu *cpu_buffer = buffer->buffers[cpu]; + struct ring_buffer_per_cpu *cpu_buffer; struct buffer_data_page *bpage = data; struct page *page = virt_to_page(bpage); unsigned long flags; + if (!buffer || !buffer->buffers || !buffer->buffers[cpu]) + return; + + cpu_buffer = buffer->buffers[cpu]; + /* If the page is still in use someplace else, we can't reuse it */ if (page_ref_count(page) > 1) goto out; From c578a68ffcdc2e8c72556bebdaae2b7500398e81 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Feb 2023 16:14:11 +0100 Subject: [PATCH 116/201] kernel/printk/index.c: fix memory leak with using debugfs_lookup() [ Upstream commit 55bf243c514553e907efcf2bda92ba090eca8c64 ] When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once. Cc: Chris Down Cc: Petr Mladek Cc: Sergey Senozhatsky Cc: Steven Rostedt Cc: John Ogness Cc: linux-kernel@vger.kernel.org Signed-off-by: Greg Kroah-Hartman Reviewed-by: Sergey Senozhatsky Reviewed-by: John Ogness Reviewed-by: Petr Mladek Signed-off-by: Petr Mladek Link: https://lore.kernel.org/r/20230202151411.2308576-1-gregkh@linuxfoundation.org Signed-off-by: Sasha Levin --- kernel/printk/index.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/printk/index.c b/kernel/printk/index.c index c85be186a783..a6b27526baaf 100644 --- a/kernel/printk/index.c +++ b/kernel/printk/index.c @@ -145,7 +145,7 @@ static void pi_create_file(struct module *mod) #ifdef CONFIG_MODULES static void pi_remove_file(struct module *mod) { - debugfs_remove(debugfs_lookup(pi_get_module_name(mod), dfs_index)); + debugfs_lookup_and_remove(pi_get_module_name(mod), dfs_index); } static int pi_module_notify(struct notifier_block *nb, unsigned long op, From a6426afbca517efd5624a036f6acf998b0b977ea Mon Sep 17 00:00:00 2001 From: Darrell Kavanagh Date: Wed, 15 Feb 2023 11:50:45 +0000 Subject: [PATCH 117/201] firmware/efi sysfb_efi: Add quirk for Lenovo IdeaPad Duet 3 [ Upstream commit e1d447157f232c650e6f32c9fb89ff3d0207c69a ] Another Lenovo convertable which reports a landscape resolution of 1920x1200 with a pitch of (1920 * 4) bytes, while the actual framebuffer has a resolution of 1200x1920 with a pitch of (1200 * 4) bytes. Signed-off-by: Darrell Kavanagh Reviewed-by: Hans de Goede Signed-off-by: Ard Biesheuvel Signed-off-by: Sasha Levin --- drivers/firmware/efi/sysfb_efi.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/firmware/efi/sysfb_efi.c b/drivers/firmware/efi/sysfb_efi.c index 7882d4b3f2be..f06fdacc9bc8 100644 --- a/drivers/firmware/efi/sysfb_efi.c +++ b/drivers/firmware/efi/sysfb_efi.c @@ -264,6 +264,14 @@ static const struct dmi_system_id efifb_dmi_swap_width_height[] __initconst = { "Lenovo ideapad D330-10IGM"), }, }, + { + /* Lenovo IdeaPad Duet 3 10IGL5 with 1200x1920 portrait screen */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, + "IdeaPad Duet 3 10IGL5"), + }, + }, {}, }; From 8caa60c20ae19797a663792ec2a439e07b4c4345 Mon Sep 17 00:00:00 2001 From: Souradeep Chowdhury Date: Wed, 22 Feb 2023 08:27:49 +0900 Subject: [PATCH 118/201] bootconfig: Increase max nodes of bootconfig from 1024 to 8192 for DCC support [ Upstream commit 6c40624930c58529185a257380442547580ed837 ] The Data Capture and Compare(DCC) is a debugging tool that uses the bootconfig for configuring the register values during boot-time. Increase the max nodes supported by bootconfig to cater to the requirements of the Data Capture and Compare Driver. Link: https://lore.kernel.org/all/1674536682-18404-1-git-send-email-quic_schowdhu@quicinc.com/ Signed-off-by: Souradeep Chowdhury Acked-by: Masami Hiramatsu (Google) Signed-off-by: Masami Hiramatsu (Google) Signed-off-by: Sasha Levin --- include/linux/bootconfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/bootconfig.h b/include/linux/bootconfig.h index 1611f9db878e..ca73940e26df 100644 --- a/include/linux/bootconfig.h +++ b/include/linux/bootconfig.h @@ -59,7 +59,7 @@ struct xbc_node { /* Maximum size of boot config is 32KB - 1 */ #define XBC_DATA_MAX (XBC_VALUE - 1) -#define XBC_NODE_MAX 1024 +#define XBC_NODE_MAX 8192 #define XBC_KEYLEN_MAX 256 #define XBC_DEPTH_MAX 16 From 9893771097b22a8743a446e45994a177795ca4da Mon Sep 17 00:00:00 2001 From: Liang He Date: Thu, 5 Jan 2023 14:10:55 +0800 Subject: [PATCH 119/201] mfd: arizona: Use pm_runtime_resume_and_get() to prevent refcnt leak [ Upstream commit 4414a7ab80cebf715045e3c4d465feefbad21139 ] In arizona_clk32k_enable(), we should use pm_runtime_resume_and_get() as pm_runtime_get_sync() will increase the refcnt even when it returns an error. Signed-off-by: Liang He Acked-by: Charles Keepax Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230105061055.1509261-1-windhl@126.com Signed-off-by: Sasha Levin --- drivers/mfd/arizona-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index cbf1dd90b70d..b1c53e040771 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -45,7 +45,7 @@ int arizona_clk32k_enable(struct arizona *arizona) if (arizona->clk32k_ref == 1) { switch (arizona->pdata.clk32k_src) { case ARIZONA_32KZ_MCLK1: - ret = pm_runtime_get_sync(arizona->dev); + ret = pm_runtime_resume_and_get(arizona->dev); if (ret != 0) goto err_ref; ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK1]); From 2ec4d5ef080024a03b9a5cd2c566e88cb2d4158e Mon Sep 17 00:00:00 2001 From: Dean Luick Date: Mon, 9 Jan 2023 14:04:29 -0500 Subject: [PATCH 120/201] IB/hfi1: Update RMT size calculation [ Upstream commit 892ede5a77f337831609fb9c248ac60948061894 ] Fix possible RMT overflow: Use the correct netdev size. Don't allow adjusted user contexts to go negative. Fix QOS calculation: Send kernel context count as an argument since dd->n_krcv_queues is not yet set up in earliest call. Do not include the control context in the QOS calculation. Use the same sized variable to find the max of krcvq[] entries. Update the RMT count explanation to make more sense. Signed-off-by: Dean Luick Signed-off-by: Dennis Dalessandro Link: https://lore.kernel.org/r/167329106946.1472990.18385495251650939054.stgit@awfm-02.cornelisnetworks.com Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- drivers/infiniband/hw/hfi1/chip.c | 59 +++++++++++++++++-------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index ebe970f76232..90b672feed83 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -1056,7 +1056,7 @@ static void read_link_down_reason(struct hfi1_devdata *dd, u8 *ldr); static void handle_temp_err(struct hfi1_devdata *dd); static void dc_shutdown(struct hfi1_devdata *dd); static void dc_start(struct hfi1_devdata *dd); -static int qos_rmt_entries(struct hfi1_devdata *dd, unsigned int *mp, +static int qos_rmt_entries(unsigned int n_krcv_queues, unsigned int *mp, unsigned int *np); static void clear_full_mgmt_pkey(struct hfi1_pportdata *ppd); static int wait_link_transfer_active(struct hfi1_devdata *dd, int wait_ms); @@ -13362,7 +13362,6 @@ static int set_up_context_variables(struct hfi1_devdata *dd) int ret; unsigned ngroups; int rmt_count; - int user_rmt_reduced; u32 n_usr_ctxts; u32 send_contexts = chip_send_contexts(dd); u32 rcv_contexts = chip_rcv_contexts(dd); @@ -13421,28 +13420,34 @@ static int set_up_context_variables(struct hfi1_devdata *dd) (num_kernel_contexts + n_usr_ctxts), &node_affinity.real_cpu_mask); /* - * The RMT entries are currently allocated as shown below: - * 1. QOS (0 to 128 entries); - * 2. FECN (num_kernel_context - 1 + num_user_contexts + - * num_netdev_contexts); - * 3. netdev (num_netdev_contexts). - * It should be noted that FECN oversubscribe num_netdev_contexts - * entries of RMT because both netdev and PSM could allocate any receive - * context between dd->first_dyn_alloc_text and dd->num_rcv_contexts, - * and PSM FECN must reserve an RMT entry for each possible PSM receive - * context. + * RMT entries are allocated as follows: + * 1. QOS (0 to 128 entries) + * 2. FECN (num_kernel_context - 1 [a] + num_user_contexts + + * num_netdev_contexts [b]) + * 3. netdev (NUM_NETDEV_MAP_ENTRIES) + * + * Notes: + * [a] Kernel contexts (except control) are included in FECN if kernel + * TID_RDMA is active. + * [b] Netdev and user contexts are randomly allocated from the same + * context pool, so FECN must cover all contexts in the pool. */ - rmt_count = qos_rmt_entries(dd, NULL, NULL) + (num_netdev_contexts * 2); - if (HFI1_CAP_IS_KSET(TID_RDMA)) - rmt_count += num_kernel_contexts - 1; - if (rmt_count + n_usr_ctxts > NUM_MAP_ENTRIES) { - user_rmt_reduced = NUM_MAP_ENTRIES - rmt_count; - dd_dev_err(dd, - "RMT size is reducing the number of user receive contexts from %u to %d\n", - n_usr_ctxts, - user_rmt_reduced); - /* recalculate */ - n_usr_ctxts = user_rmt_reduced; + rmt_count = qos_rmt_entries(num_kernel_contexts - 1, NULL, NULL) + + (HFI1_CAP_IS_KSET(TID_RDMA) ? num_kernel_contexts - 1 + : 0) + + n_usr_ctxts + + num_netdev_contexts + + NUM_NETDEV_MAP_ENTRIES; + if (rmt_count > NUM_MAP_ENTRIES) { + int over = rmt_count - NUM_MAP_ENTRIES; + /* try to squish user contexts, minimum of 1 */ + if (over >= n_usr_ctxts) { + dd_dev_err(dd, "RMT overflow: reduce the requested number of contexts\n"); + return -EINVAL; + } + dd_dev_err(dd, "RMT overflow: reducing # user contexts from %u to %u\n", + n_usr_ctxts, n_usr_ctxts - over); + n_usr_ctxts -= over; } /* the first N are kernel contexts, the rest are user/netdev contexts */ @@ -14299,15 +14304,15 @@ static void clear_rsm_rule(struct hfi1_devdata *dd, u8 rule_index) } /* return the number of RSM map table entries that will be used for QOS */ -static int qos_rmt_entries(struct hfi1_devdata *dd, unsigned int *mp, +static int qos_rmt_entries(unsigned int n_krcv_queues, unsigned int *mp, unsigned int *np) { int i; unsigned int m, n; - u8 max_by_vl = 0; + uint max_by_vl = 0; /* is QOS active at all? */ - if (dd->n_krcv_queues <= MIN_KERNEL_KCTXTS || + if (n_krcv_queues < MIN_KERNEL_KCTXTS || num_vls == 1 || krcvqsset <= 1) goto no_qos; @@ -14365,7 +14370,7 @@ static void init_qos(struct hfi1_devdata *dd, struct rsm_map_table *rmt) if (!rmt) goto bail; - rmt_entries = qos_rmt_entries(dd, &m, &n); + rmt_entries = qos_rmt_entries(dd->n_krcv_queues - 1, &m, &n); if (rmt_entries == 0) goto bail; qpns_per_vl = 1 << m; From 60ac0a6de6b06c20ee9c684e7f1c080d8f9fb564 Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Wed, 11 Jan 2023 12:15:03 +0000 Subject: [PATCH 121/201] iommu/amd: Fix error handling for pdev_pri_ats_enable() [ Upstream commit 080920e52148b4fbbf9360d5345fdcd7846e4841 ] Current code throws kernel warning if it fails to enable pasid/pri [1]. Do not call pci_disable_[pasid/pri] if pci_enable_[pasid/pri] failed. [1] https://lore.kernel.org/linux-iommu/15d0f9ff-2a56-b3e9-5b45-e6b23300ae3b@leemhuis.info/ Reported-by: Matt Fagnani Signed-off-by: Vasant Hegde Reviewed-by: Suravee Suthikulpanit Link: https://lore.kernel.org/r/20230111121503.5931-1-vasant.hegde@amd.com Signed-off-by: Joerg Roedel Signed-off-by: Sasha Levin --- drivers/iommu/amd/iommu.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 968e5e6668b2..20adb9b323d8 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -1712,27 +1712,29 @@ static int pdev_pri_ats_enable(struct pci_dev *pdev) /* Only allow access to user-accessible pages */ ret = pci_enable_pasid(pdev, 0); if (ret) - goto out_err; + return ret; /* First reset the PRI state of the device */ ret = pci_reset_pri(pdev); if (ret) - goto out_err; + goto out_err_pasid; /* Enable PRI */ /* FIXME: Hardcode number of outstanding requests for now */ ret = pci_enable_pri(pdev, 32); if (ret) - goto out_err; + goto out_err_pasid; ret = pci_enable_ats(pdev, PAGE_SHIFT); if (ret) - goto out_err; + goto out_err_pri; return 0; -out_err: +out_err_pri: pci_disable_pri(pdev); + +out_err_pasid: pci_disable_pasid(pdev); return ret; From 7b41160db12083e6a0231c64f626c6011c1f7e3b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 12 Jan 2023 21:51:24 +0100 Subject: [PATCH 122/201] PCI/ACPI: Account for _S0W of the target bridge in acpi_pci_bridge_d3() [ Upstream commit 8133844a8f2434be9576850c6978179d7cca5c81 ] It is questionable to allow a PCI bridge to go into D3 if it has _S0W returning D2 or a shallower power state, so modify acpi_pci_bridge_d3(() to always take the return value of _S0W for the target bridge into account. That is, make it return 'false' if _S0W returns D2 or a shallower power state for the target bridge regardless of its ancestor Root Port properties. Of course, this also causes 'false' to be returned if the Root Port itself is the target and its _S0W returns D2 or a shallower power state. However, still allow bridges without _S0W that are power-manageable via ACPI to enter D3 to retain the current code behavior in that case. This fixes problems where a hotplug notification is missed because a bridge is in D3. That means hot-added devices such as USB4 docks (and the devices they contain) and Thunderbolt 3 devices may not work. Link: https://lore.kernel.org/linux-pci/20221031223356.32570-1-mario.limonciello@amd.com/ Link: https://lore.kernel.org/r/12155458.O9o76ZdvQC@kreacher Reported-by: Mario Limonciello Signed-off-by: Rafael J. Wysocki Signed-off-by: Bjorn Helgaas Signed-off-by: Sasha Levin --- drivers/acpi/device_pm.c | 19 +++++++++++++++++ drivers/pci/pci-acpi.c | 45 +++++++++++++++++++++++++++------------- include/acpi/acpi_bus.h | 1 + 3 files changed, 51 insertions(+), 14 deletions(-) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 97450f4003cc..f007116a8427 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -484,6 +484,25 @@ void acpi_dev_power_up_children_with_adr(struct acpi_device *adev) acpi_dev_for_each_child(adev, acpi_power_up_if_adr_present, NULL); } +/** + * acpi_dev_power_state_for_wake - Deepest power state for wakeup signaling + * @adev: ACPI companion of the target device. + * + * Evaluate _S0W for @adev and return the value produced by it or return + * ACPI_STATE_UNKNOWN on errors (including _S0W not present). + */ +u8 acpi_dev_power_state_for_wake(struct acpi_device *adev) +{ + unsigned long long state; + acpi_status status; + + status = acpi_evaluate_integer(adev->handle, "_S0W", NULL, &state); + if (ACPI_FAILURE(status)) + return ACPI_STATE_UNKNOWN; + + return state; +} + #ifdef CONFIG_PM static DEFINE_MUTEX(acpi_pm_notifier_lock); static DEFINE_MUTEX(acpi_pm_notifier_install_lock); diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index a46fec776ad7..1698205dd73c 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -976,24 +976,41 @@ bool acpi_pci_power_manageable(struct pci_dev *dev) bool acpi_pci_bridge_d3(struct pci_dev *dev) { struct pci_dev *rpdev; - struct acpi_device *adev; - acpi_status status; - unsigned long long state; + struct acpi_device *adev, *rpadev; const union acpi_object *obj; if (acpi_pci_disabled || !dev->is_hotplug_bridge) return false; - /* Assume D3 support if the bridge is power-manageable by ACPI. */ - if (acpi_pci_power_manageable(dev)) - return true; + adev = ACPI_COMPANION(&dev->dev); + if (adev) { + /* + * If the bridge has _S0W, whether or not it can go into D3 + * depends on what is returned by that object. In particular, + * if the power state returned by _S0W is D2 or shallower, + * entering D3 should not be allowed. + */ + if (acpi_dev_power_state_for_wake(adev) <= ACPI_STATE_D2) + return false; + + /* + * Otherwise, assume that the bridge can enter D3 so long as it + * is power-manageable via ACPI. + */ + if (acpi_device_power_manageable(adev)) + return true; + } rpdev = pcie_find_root_port(dev); if (!rpdev) return false; - adev = ACPI_COMPANION(&rpdev->dev); - if (!adev) + if (rpdev == dev) + rpadev = adev; + else + rpadev = ACPI_COMPANION(&rpdev->dev); + + if (!rpadev) return false; /* @@ -1001,15 +1018,15 @@ bool acpi_pci_bridge_d3(struct pci_dev *dev) * doesn't supply a wakeup GPE via _PRW, it cannot signal hotplug * events from low-power states including D3hot and D3cold. */ - if (!adev->wakeup.flags.valid) + if (!rpadev->wakeup.flags.valid) return false; /* - * If the Root Port cannot wake itself from D3hot or D3cold, we - * can't use D3. + * In the bridge-below-a-Root-Port case, evaluate _S0W for the Root Port + * to verify whether or not it can signal wakeup from D3. */ - status = acpi_evaluate_integer(adev->handle, "_S0W", NULL, &state); - if (ACPI_SUCCESS(status) && state < ACPI_STATE_D3_HOT) + if (rpadev != adev && + acpi_dev_power_state_for_wake(rpadev) <= ACPI_STATE_D2) return false; /* @@ -1018,7 +1035,7 @@ bool acpi_pci_bridge_d3(struct pci_dev *dev) * bridges *below* that Root Port can also signal hotplug events * while in D3. */ - if (!acpi_dev_get_property(adev, "HotPlugSupportInD3", + if (!acpi_dev_get_property(rpadev, "HotPlugSupportInD3", ACPI_TYPE_INTEGER, &obj) && obj->integer.value == 1) return true; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index ab2d6266038a..6badc50ec4e6 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -534,6 +534,7 @@ int acpi_bus_update_power(acpi_handle handle, int *state_p); int acpi_device_update_power(struct acpi_device *device, int *state_p); bool acpi_bus_power_manageable(acpi_handle handle); void acpi_dev_power_up_children_with_adr(struct acpi_device *adev); +u8 acpi_dev_power_state_for_wake(struct acpi_device *adev); int acpi_device_power_add_dependent(struct acpi_device *adev, struct device *dev); void acpi_device_power_remove_dependent(struct acpi_device *adev, From 2c8ea08b86a5789449c5eb3da23e3864bb58c16a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 15 Nov 2016 18:44:29 +0200 Subject: [PATCH 123/201] media: uvcvideo: Remove format descriptions [ Upstream commit 50459f103edfe47c9a599d766a850ef6014936c5 ] The V4L2 core overwrites format descriptions in v4l_fill_fmtdesc(), there's no need to manually set the descriptions in the driver. This prepares for removal of the format descriptions from the uvc_fmts table. Unlike V4L2, UVC makes a distinction between the SD-DV, SDL-DV and HD-DV formats. It also indicates whether the DV format uses 50Hz or 60Hz. This information is parsed by the driver to construct a format name string that is printed in a debug message, but serves no other purpose as V4L2 has a single V4L2_PIX_FMT_DV pixel format that covers all those cases. As the information is available in the UVC descriptors, and thus accessible to users with lsusb if they really care, don't log it in a debug message and drop the format name string to simplify the code. Signed-off-by: Laurent Pinchart Reviewed-by: Ricardo Ribalda Reviewed-by: Michael Grzeschik Signed-off-by: Sasha Levin --- drivers/media/usb/uvc/uvc_driver.c | 24 ++---------------------- drivers/media/usb/uvc/uvc_v4l2.c | 2 -- drivers/media/usb/uvc/uvcvideo.h | 2 -- 3 files changed, 2 insertions(+), 26 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index abfe735f6ea3..16c75b863545 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -252,14 +252,10 @@ static int uvc_parse_format(struct uvc_device *dev, fmtdesc = uvc_format_by_guid(&buffer[5]); if (fmtdesc != NULL) { - strscpy(format->name, fmtdesc->name, - sizeof(format->name)); format->fcc = fmtdesc->fcc; } else { dev_info(&streaming->intf->dev, "Unknown video format %pUl\n", &buffer[5]); - snprintf(format->name, sizeof(format->name), "%pUl\n", - &buffer[5]); format->fcc = 0; } @@ -271,8 +267,6 @@ static int uvc_parse_format(struct uvc_device *dev, */ if (dev->quirks & UVC_QUIRK_FORCE_Y8) { if (format->fcc == V4L2_PIX_FMT_YUYV) { - strscpy(format->name, "Greyscale 8-bit (Y8 )", - sizeof(format->name)); format->fcc = V4L2_PIX_FMT_GREY; format->bpp = 8; width_multiplier = 2; @@ -313,7 +307,6 @@ static int uvc_parse_format(struct uvc_device *dev, return -EINVAL; } - strscpy(format->name, "MJPEG", sizeof(format->name)); format->fcc = V4L2_PIX_FMT_MJPEG; format->flags = UVC_FMT_FLAG_COMPRESSED; format->bpp = 0; @@ -329,17 +322,7 @@ static int uvc_parse_format(struct uvc_device *dev, return -EINVAL; } - switch (buffer[8] & 0x7f) { - case 0: - strscpy(format->name, "SD-DV", sizeof(format->name)); - break; - case 1: - strscpy(format->name, "SDL-DV", sizeof(format->name)); - break; - case 2: - strscpy(format->name, "HD-DV", sizeof(format->name)); - break; - default: + if ((buffer[8] & 0x7f) > 2) { uvc_dbg(dev, DESCR, "device %d videostreaming interface %d: unknown DV format %u\n", dev->udev->devnum, @@ -347,9 +330,6 @@ static int uvc_parse_format(struct uvc_device *dev, return -EINVAL; } - strlcat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz", - sizeof(format->name)); - format->fcc = V4L2_PIX_FMT_DV; format->flags = UVC_FMT_FLAG_COMPRESSED | UVC_FMT_FLAG_STREAM; format->bpp = 0; @@ -376,7 +356,7 @@ static int uvc_parse_format(struct uvc_device *dev, return -EINVAL; } - uvc_dbg(dev, DESCR, "Found format %s\n", format->name); + uvc_dbg(dev, DESCR, "Found format %p4cc", &format->fcc); buflen -= buffer[0]; buffer += buffer[0]; diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 0774a11360c0..950b42d78a10 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -661,8 +661,6 @@ static int uvc_ioctl_enum_fmt(struct uvc_streaming *stream, fmt->flags = 0; if (format->flags & UVC_FMT_FLAG_COMPRESSED) fmt->flags |= V4L2_FMT_FLAG_COMPRESSED; - strscpy(fmt->description, format->name, sizeof(fmt->description)); - fmt->description[sizeof(fmt->description) - 1] = 0; fmt->pixelformat = format->fcc; return 0; } diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 1227ae63f85b..4c89bf08171f 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -264,8 +264,6 @@ struct uvc_format { u32 fcc; u32 flags; - char name[32]; - unsigned int nframes; struct uvc_frame *frame; }; From 11196ee3916e50a5da3c1e6ecda19a02dca14ba3 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Tue, 20 Sep 2022 16:04:55 +0200 Subject: [PATCH 124/201] media: uvcvideo: Handle cameras with invalid descriptors [ Upstream commit 41ddb251c68ac75c101d3a50a68c4629c9055e4c ] If the source entity does not contain any pads, do not create a link. Reported-by: syzbot Signed-off-by: Ricardo Ribalda Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Sasha Levin --- drivers/media/usb/uvc/uvc_entity.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c index 7c4d2f93d351..cc68dd24eb42 100644 --- a/drivers/media/usb/uvc/uvc_entity.c +++ b/drivers/media/usb/uvc/uvc_entity.c @@ -37,7 +37,7 @@ static int uvc_mc_create_links(struct uvc_video_chain *chain, continue; remote = uvc_entity_by_id(chain->dev, entity->baSourceID[i]); - if (remote == NULL) + if (remote == NULL || remote->num_pads == 0) return -EINVAL; source = (UVC_ENTITY_TYPE(remote) == UVC_TT_STREAMING) From acfed4676a5900264927380ed32d921cd4059d6b Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 25 Oct 2022 16:41:01 +0200 Subject: [PATCH 125/201] media: uvcvideo: Handle errors from calls to usb_string [ Upstream commit 4867bb590ae445bcfaa711a86b603c97e94574b3 ] On a Webcam from Quanta, we see the following error. usb 3-5: New USB device found, idVendor=0408, idProduct=30d2, bcdDevice= 0.03 usb 3-5: New USB device strings: Mfr=3, Product=1, SerialNumber=2 usb 3-5: Product: USB2.0 HD UVC WebCam usb 3-5: Manufacturer: Quanta usb 3-5: SerialNumber: 0x0001 ... uvcvideo: Found UVC 1.10 device USB2.0 HD UVC WebCam (0408:30d2) uvcvideo: Failed to initialize entity for entity 5 uvcvideo: Failed to register entities (-22). The Webcam reports an entity of type UVC_VC_EXTENSION_UNIT. It reports a string index of '7' associated with that entity. The attempt to read that string from the camera fails with error -32 (-EPIPE). usb_string() returns that error, but it is ignored. As result, the entity name is empty. This later causes v4l2_device_register_subdev() to return -EINVAL, and no entities are registered as result. While this appears to be a firmware problem with the camera, the kernel should still handle the situation gracefully. To do that, check the return value from usb_string(). If it reports an error, assign the entity's default name. Signed-off-by: Guenter Roeck Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Sasha Levin --- drivers/media/usb/uvc/uvc_driver.c | 48 ++++++++++++------------------ 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 16c75b863545..ef08e5f51ede 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -860,10 +860,8 @@ static int uvc_parse_vendor_control(struct uvc_device *dev, + n; memcpy(unit->extension.bmControls, &buffer[23+p], 2*n); - if (buffer[24+p+2*n] != 0) - usb_string(udev, buffer[24+p+2*n], unit->name, - sizeof(unit->name)); - else + if (buffer[24+p+2*n] == 0 || + usb_string(udev, buffer[24+p+2*n], unit->name, sizeof(unit->name)) < 0) sprintf(unit->name, "Extension %u", buffer[3]); list_add_tail(&unit->list, &dev->entities); @@ -987,15 +985,15 @@ static int uvc_parse_standard_control(struct uvc_device *dev, memcpy(term->media.bmTransportModes, &buffer[10+n], p); } - if (buffer[7] != 0) - usb_string(udev, buffer[7], term->name, - sizeof(term->name)); - else if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) - sprintf(term->name, "Camera %u", buffer[3]); - else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT) - sprintf(term->name, "Media %u", buffer[3]); - else - sprintf(term->name, "Input %u", buffer[3]); + if (buffer[7] == 0 || + usb_string(udev, buffer[7], term->name, sizeof(term->name)) < 0) { + if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) + sprintf(term->name, "Camera %u", buffer[3]); + if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT) + sprintf(term->name, "Media %u", buffer[3]); + else + sprintf(term->name, "Input %u", buffer[3]); + } list_add_tail(&term->list, &dev->entities); break; @@ -1028,10 +1026,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev, memcpy(term->baSourceID, &buffer[7], 1); - if (buffer[8] != 0) - usb_string(udev, buffer[8], term->name, - sizeof(term->name)); - else + if (buffer[8] == 0 || + usb_string(udev, buffer[8], term->name, sizeof(term->name)) < 0) sprintf(term->name, "Output %u", buffer[3]); list_add_tail(&term->list, &dev->entities); @@ -1053,10 +1049,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev, memcpy(unit->baSourceID, &buffer[5], p); - if (buffer[5+p] != 0) - usb_string(udev, buffer[5+p], unit->name, - sizeof(unit->name)); - else + if (buffer[5+p] == 0 || + usb_string(udev, buffer[5+p], unit->name, sizeof(unit->name)) < 0) sprintf(unit->name, "Selector %u", buffer[3]); list_add_tail(&unit->list, &dev->entities); @@ -1086,10 +1080,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev, if (dev->uvc_version >= 0x0110) unit->processing.bmVideoStandards = buffer[9+n]; - if (buffer[8+n] != 0) - usb_string(udev, buffer[8+n], unit->name, - sizeof(unit->name)); - else + if (buffer[8+n] == 0 || + usb_string(udev, buffer[8+n], unit->name, sizeof(unit->name)) < 0) sprintf(unit->name, "Processing %u", buffer[3]); list_add_tail(&unit->list, &dev->entities); @@ -1117,10 +1109,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev, unit->extension.bmControls = (u8 *)unit + sizeof(*unit); memcpy(unit->extension.bmControls, &buffer[23+p], n); - if (buffer[23+p+n] != 0) - usb_string(udev, buffer[23+p+n], unit->name, - sizeof(unit->name)); - else + if (buffer[23+p+n] == 0 || + usb_string(udev, buffer[23+p+n], unit->name, sizeof(unit->name)) < 0) sprintf(unit->name, "Extension %u", buffer[3]); list_add_tail(&unit->list, &dev->entities); From 3c4a3bbe025cb2c5a54548bc4d338e0c8d15dc5b Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Wed, 4 Jan 2023 11:45:23 +0100 Subject: [PATCH 126/201] media: uvcvideo: Quirk for autosuspend in Logitech B910 and C910 [ Upstream commit 136effa754b57632f99574fc4a3433e0cfc031d9 ] Logitech B910 and C910 firmware are unable to recover from a USB autosuspend. When it resumes, the device is in a state where it only produces invalid frames. Eg: $ echo 0xFFFF > /sys/module/uvcvideo/parameters/trace # enable verbose log $ yavta -c1 -n1 --file='frame#.jpg' --format MJPEG --size=1920x1080 /dev/video1 [350438.435219] uvcvideo: uvc_v4l2_open [350438.529794] uvcvideo: Resuming interface 2 [350438.529801] uvcvideo: Resuming interface 3 [350438.529991] uvcvideo: Trying format 0x47504a4d (MJPG): 1920x1080. [350438.529996] uvcvideo: Using default frame interval 33333.3 us (30.0 fps). [350438.551496] uvcvideo: uvc_v4l2_mmap [350438.555890] uvcvideo: Device requested 3060 B/frame bandwidth. [350438.555896] uvcvideo: Selecting alternate setting 11 (3060 B/frame bandwidth). [350438.556362] uvcvideo: Allocated 5 URB buffers of 32x3060 bytes each. [350439.316468] uvcvideo: Marking buffer as bad (error bit set). [350439.316475] uvcvideo: Frame complete (EOF found). [350439.316477] uvcvideo: EOF in empty payload. [350439.316484] uvcvideo: frame 1 stats: 149/261/417 packets, 1/149/417 pts (early initial), 416/417 scr, last pts/stc/sof 2976325734/2978107243/249 [350439.384510] uvcvideo: Marking buffer as bad (error bit set). [350439.384516] uvcvideo: Frame complete (EOF found). [350439.384518] uvcvideo: EOF in empty payload. [350439.384525] uvcvideo: frame 2 stats: 265/379/533 packets, 1/265/533 pts (early initial), 532/533 scr, last pts/stc/sof 2979524454/2981305193/316 [350439.448472] uvcvideo: Marking buffer as bad (error bit set). [350439.448478] uvcvideo: Frame complete (EOF found). [350439.448480] uvcvideo: EOF in empty payload. [350439.448487] uvcvideo: frame 3 stats: 265/377/533 packets, 1/265/533 pts (early initial), 532/533 scr, last pts/stc/sof 2982723174/2984503144/382 ...(loop)... The devices can leave this invalid state if the alternate setting of the streaming interface is toggled. This patch adds a quirk for this device so it can be autosuspended properly. lsusb -v: Bus 001 Device 049: ID 046d:0821 Logitech, Inc. HD Webcam C910 Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 239 Miscellaneous Device bDeviceSubClass 2 bDeviceProtocol 1 Interface Association bMaxPacketSize0 64 idVendor 0x046d Logitech, Inc. idProduct 0x0821 HD Webcam C910 bcdDevice 0.10 iManufacturer 0 iProduct 0 iSerial 1 390022B0 bNumConfigurations 1 Signed-off-by: Ricardo Ribalda Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Sasha Levin --- drivers/media/usb/uvc/uvc_driver.c | 18 ++++++++++++++++++ drivers/media/usb/uvc/uvc_video.c | 11 +++++++++++ drivers/media/usb/uvc/uvcvideo.h | 1 + 3 files changed, 30 insertions(+) diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index ef08e5f51ede..a9cdef07e6b1 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -2453,6 +2453,24 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = (kernel_ulong_t)&uvc_quirk_probe_minmax }, + /* Logitech, Webcam C910 */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x046d, + .idProduct = 0x0821, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_WAKE_AUTOSUSPEND)}, + /* Logitech, Webcam B910 */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x046d, + .idProduct = 0x0823, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_WAKE_AUTOSUSPEND)}, /* Logitech Quickcam Fusion */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index d2eb9066e4dc..53ea22597247 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1965,6 +1965,17 @@ static int uvc_video_start_transfer(struct uvc_streaming *stream, "Selecting alternate setting %u (%u B/frame bandwidth)\n", altsetting, best_psize); + /* + * Some devices, namely the Logitech C910 and B910, are unable + * to recover from a USB autosuspend, unless the alternate + * setting of the streaming interface is toggled. + */ + if (stream->dev->quirks & UVC_QUIRK_WAKE_AUTOSUSPEND) { + usb_set_interface(stream->dev->udev, intfnum, + altsetting); + usb_set_interface(stream->dev->udev, intfnum, 0); + } + ret = usb_set_interface(stream->dev->udev, intfnum, altsetting); if (ret < 0) return ret; diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 4c89bf08171f..b0937703c725 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -74,6 +74,7 @@ #define UVC_QUIRK_RESTORE_CTRLS_ON_INIT 0x00000400 #define UVC_QUIRK_FORCE_Y8 0x00000800 #define UVC_QUIRK_FORCE_BPP 0x00001000 +#define UVC_QUIRK_WAKE_AUTOSUSPEND 0x00002000 /* Format flags */ #define UVC_FMT_FLAG_COMPRESSED 0x00000001 From 15aed90f3e0539ff36e105d8867c8075074c924f Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 5 Jan 2023 22:17:04 -0800 Subject: [PATCH 127/201] media: uvcvideo: Silence memcpy() run-time false positive warnings [ Upstream commit b839212988575c701aab4d3d9ca15e44c87e383c ] The memcpy() in uvc_video_decode_meta() intentionally copies across the length and flags members and into the trailing buf flexible array. Split the copy so that the compiler can better reason about (the lack of) buffer overflows here. Avoid the run-time false positive warning: memcpy: detected field-spanning write (size 12) of single field "&meta->length" at drivers/media/usb/uvc/uvc_video.c:1355 (size 1) Additionally fix a typo in the documentation for struct uvc_meta_buf. Reported-by: ionut_n2001@yahoo.com Link: https://bugzilla.kernel.org/show_bug.cgi?id=216810 Signed-off-by: Kees Cook Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Sasha Levin --- drivers/media/usb/uvc/uvc_video.c | 4 +++- include/uapi/linux/uvcvideo.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 53ea22597247..0d3a3b697b2d 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1352,7 +1352,9 @@ static void uvc_video_decode_meta(struct uvc_streaming *stream, if (has_scr) memcpy(stream->clock.last_scr, scr, 6); - memcpy(&meta->length, mem, length); + meta->length = mem[0]; + meta->flags = mem[1]; + memcpy(meta->buf, &mem[2], length - 2); meta_buf->bytesused += length + sizeof(meta->ns) + sizeof(meta->sof); uvc_dbg(stream->dev, FRAME, diff --git a/include/uapi/linux/uvcvideo.h b/include/uapi/linux/uvcvideo.h index 8288137387c0..a9d0a64007ba 100644 --- a/include/uapi/linux/uvcvideo.h +++ b/include/uapi/linux/uvcvideo.h @@ -86,7 +86,7 @@ struct uvc_xu_control_query { * struct. The first two fields are added by the driver, they can be used for * clock synchronisation. The rest is an exact copy of a UVC payload header. * Only complete objects with complete buffers are included. Therefore it's - * always sizeof(meta->ts) + sizeof(meta->sof) + meta->length bytes large. + * always sizeof(meta->ns) + sizeof(meta->sof) + meta->length bytes large. */ struct uvc_meta_buf { __u64 ns; From c68ece7baf2aa9783b8244482c03010d477d4a93 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 6 Jan 2023 16:28:28 +0100 Subject: [PATCH 128/201] USB: fix memory leak with using debugfs_lookup() [ Upstream commit 30374434edab20e25776f8ecb4bc9d1e54309487 ] When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once. Cc: Alan Stern Cc: Jilin Yuan Link: https://lore.kernel.org/r/20230106152828.3790902-1-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/core/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 11b15d7b357a..a415206cab04 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -998,7 +998,7 @@ static void usb_debugfs_init(void) static void usb_debugfs_cleanup(void) { - debugfs_remove(debugfs_lookup("devices", usb_debug_root)); + debugfs_lookup_and_remove("devices", usb_debug_root); } /* From 2f588d0345d69a35e451077afed428fd057a5e34 Mon Sep 17 00:00:00 2001 From: Yong-Xuan Wang Date: Tue, 17 Jan 2023 10:51:33 +0000 Subject: [PATCH 129/201] cacheinfo: Fix shared_cpu_map to handle shared caches at different levels [ Upstream commit 198102c9103fc78d8478495971947af77edb05c1 ] The cacheinfo sets up the shared_cpu_map by checking whether the caches with the same index are shared between CPUs. However, this will trigger slab-out-of-bounds access if the CPUs do not have the same cache hierarchy. Another problem is the mismatched shared_cpu_map when the shared cache does not have the same index between CPUs. CPU0 I D L3 index 0 1 2 x ^ ^ ^ ^ index 0 1 2 3 CPU1 I D L2 L3 This patch checks each cache is shared with all caches on other CPUs. Reviewed-by: Pierre Gondois Signed-off-by: Yong-Xuan Wang Link: https://lore.kernel.org/r/20230117105133.4445-2-yongxuan.wang@sifive.com Signed-off-by: Sudeep Holla Signed-off-by: Sasha Levin --- drivers/base/cacheinfo.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index 4b5cd08c5a65..f30256a524be 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -251,7 +251,7 @@ static int cache_shared_cpu_map_setup(unsigned int cpu) { struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); struct cacheinfo *this_leaf, *sib_leaf; - unsigned int index; + unsigned int index, sib_index; int ret = 0; if (this_cpu_ci->cpu_map_populated) @@ -279,11 +279,13 @@ static int cache_shared_cpu_map_setup(unsigned int cpu) if (i == cpu || !sib_cpu_ci->info_list) continue;/* skip if itself or no cacheinfo */ - - sib_leaf = per_cpu_cacheinfo_idx(i, index); - if (cache_leaves_are_shared(this_leaf, sib_leaf)) { - cpumask_set_cpu(cpu, &sib_leaf->shared_cpu_map); - cpumask_set_cpu(i, &this_leaf->shared_cpu_map); + for (sib_index = 0; sib_index < cache_leaves(i); sib_index++) { + sib_leaf = per_cpu_cacheinfo_idx(i, sib_index); + if (cache_leaves_are_shared(this_leaf, sib_leaf)) { + cpumask_set_cpu(cpu, &sib_leaf->shared_cpu_map); + cpumask_set_cpu(i, &this_leaf->shared_cpu_map); + break; + } } } /* record the maximum cache line size */ @@ -297,7 +299,7 @@ static int cache_shared_cpu_map_setup(unsigned int cpu) static void cache_shared_cpu_map_remove(unsigned int cpu) { struct cacheinfo *this_leaf, *sib_leaf; - unsigned int sibling, index; + unsigned int sibling, index, sib_index; for (index = 0; index < cache_leaves(cpu); index++) { this_leaf = per_cpu_cacheinfo_idx(cpu, index); @@ -308,9 +310,14 @@ static void cache_shared_cpu_map_remove(unsigned int cpu) if (sibling == cpu || !sib_cpu_ci->info_list) continue;/* skip if itself or no cacheinfo */ - sib_leaf = per_cpu_cacheinfo_idx(sibling, index); - cpumask_clear_cpu(cpu, &sib_leaf->shared_cpu_map); - cpumask_clear_cpu(sibling, &this_leaf->shared_cpu_map); + for (sib_index = 0; sib_index < cache_leaves(sibling); sib_index++) { + sib_leaf = per_cpu_cacheinfo_idx(sibling, sib_index); + if (cache_leaves_are_shared(this_leaf, sib_leaf)) { + cpumask_clear_cpu(cpu, &sib_leaf->shared_cpu_map); + cpumask_clear_cpu(sibling, &this_leaf->shared_cpu_map); + break; + } + } } if (of_have_populated_dt()) of_node_put(this_leaf->fw_token); From 3c8dce696a660a3d704add7e11c9987dd6649eca Mon Sep 17 00:00:00 2001 From: Yuan Can Date: Thu, 19 Jan 2023 08:31:19 +0000 Subject: [PATCH 130/201] staging: emxx_udc: Add checks for dma_alloc_coherent() [ Upstream commit f6510a93cfd8c6c79b4dda0f2967cdc6df42eff4 ] As the dma_alloc_coherent may return NULL, the return value needs to be checked to avoid NULL poineter dereference. Signed-off-by: Yuan Can Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230119083119.16956-1-yuancan@huawei.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/staging/emxx_udc/emxx_udc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/staging/emxx_udc/emxx_udc.c b/drivers/staging/emxx_udc/emxx_udc.c index b6abd3770e81..edd20a03f7a2 100644 --- a/drivers/staging/emxx_udc/emxx_udc.c +++ b/drivers/staging/emxx_udc/emxx_udc.c @@ -2590,10 +2590,15 @@ static int nbu2ss_ep_queue(struct usb_ep *_ep, req->unaligned = false; if (req->unaligned) { - if (!ep->virt_buf) + if (!ep->virt_buf) { ep->virt_buf = dma_alloc_coherent(udc->dev, PAGE_SIZE, &ep->phys_buf, GFP_ATOMIC | GFP_DMA); + if (!ep->virt_buf) { + spin_unlock_irqrestore(&udc->lock, flags); + return -ENOMEM; + } + } if (ep->epnum > 0) { if (ep->direct == USB_DIR_IN) memcpy(ep->virt_buf, req->req.buf, From 765566110eb0da3cf60198b0165ecceeaafa6444 Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Fri, 9 Dec 2022 12:27:36 +0100 Subject: [PATCH 131/201] tty: fix out-of-bounds access in tty_driver_lookup_tty() [ Upstream commit db4df8e9d79e7d37732c1a1b560958e8dadfefa1 ] When specifying an invalid console= device like console=tty3270, tty_driver_lookup_tty() returns the tty struct without checking whether index is a valid number. To reproduce: qemu-system-x86_64 -enable-kvm -nographic -serial mon:stdio \ -kernel ../linux-build-x86/arch/x86/boot/bzImage \ -append "console=ttyS0 console=tty3270" This crashes with: [ 0.770599] BUG: kernel NULL pointer dereference, address: 00000000000000ef [ 0.771265] #PF: supervisor read access in kernel mode [ 0.771773] #PF: error_code(0x0000) - not-present page [ 0.772609] Oops: 0000 [#1] PREEMPT SMP PTI [ 0.774878] RIP: 0010:tty_open+0x268/0x6f0 [ 0.784013] chrdev_open+0xbd/0x230 [ 0.784444] ? cdev_device_add+0x80/0x80 [ 0.784920] do_dentry_open+0x1e0/0x410 [ 0.785389] path_openat+0xca9/0x1050 [ 0.785813] do_filp_open+0xaa/0x150 [ 0.786240] file_open_name+0x133/0x1b0 [ 0.786746] filp_open+0x27/0x50 [ 0.787244] console_on_rootfs+0x14/0x4d [ 0.787800] kernel_init_freeable+0x1e4/0x20d [ 0.788383] ? rest_init+0xc0/0xc0 [ 0.788881] kernel_init+0x11/0x120 [ 0.789356] ret_from_fork+0x22/0x30 Signed-off-by: Sven Schnelle Reviewed-by: Jiri Slaby Link: https://lore.kernel.org/r/20221209112737.3222509-2-svens@linux.ibm.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/tty/tty_io.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index de06c3c2ff70..1ac6784ea1f9 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1224,14 +1224,16 @@ static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver, { struct tty_struct *tty; - if (driver->ops->lookup) + if (driver->ops->lookup) { if (!file) tty = ERR_PTR(-EIO); else tty = driver->ops->lookup(driver, file, idx); - else + } else { + if (idx >= driver->num) + return ERR_PTR(-EINVAL); tty = driver->ttys[idx]; - + } if (!IS_ERR(tty)) tty_kref_get(tty); return tty; From 59aba03932753558a2d2cb90a0582d5f2ae17fdf Mon Sep 17 00:00:00 2001 From: Sherry Sun Date: Wed, 14 Dec 2022 11:11:35 +0800 Subject: [PATCH 132/201] tty: serial: fsl_lpuart: disable the CTS when send break signal [ Upstream commit c4c81db5cf8bc53d6160c3abf26d382c841aa434 ] LPUART IP has a bug that it treats the CTS as higher priority than the break signal, which cause the break signal sending through UARTCTRL_SBK may impacted by the CTS input if the HW flow control is enabled. Add this workaround patch to fix the IP bug, we can disable CTS before asserting SBK to avoid any interference from CTS, and re-enable it when break off. Such as for the bluetooth chip power save feature, host can let the BT chip get into sleep state by sending a UART break signal, and wake it up by turning off the UART break. If the BT chip enters the sleep mode successfully, it will pull up the CTS line, if the BT chip is woken up, it will pull down the CTS line. If without this workaround patch, the UART TX pin cannot send the break signal successfully as it affected by the BT CTS pin. After adding this patch, the BT power save feature can work well. Signed-off-by: Sherry Sun Link: https://lore.kernel.org/r/20221214031137.28815-2-sherry.sun@nxp.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/tty/serial/fsl_lpuart.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 13a6cd0116a1..f9d667ce1619 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1468,12 +1468,32 @@ static void lpuart_break_ctl(struct uart_port *port, int break_state) static void lpuart32_break_ctl(struct uart_port *port, int break_state) { - unsigned long temp; + unsigned long temp, modem; + struct tty_struct *tty; + unsigned int cflag = 0; + + tty = tty_port_tty_get(&port->state->port); + if (tty) { + cflag = tty->termios.c_cflag; + tty_kref_put(tty); + } temp = lpuart32_read(port, UARTCTRL) & ~UARTCTRL_SBK; + modem = lpuart32_read(port, UARTMODIR); - if (break_state != 0) + if (break_state != 0) { temp |= UARTCTRL_SBK; + /* + * LPUART CTS has higher priority than SBK, need to disable CTS before + * asserting SBK to avoid any interference if flow control is enabled. + */ + if (cflag & CRTSCTS && modem & UARTMODIR_TXCTSE) + lpuart32_write(port, modem & ~UARTMODIR_TXCTSE, UARTMODIR); + } else { + /* Re-enable the CTS when break off. */ + if (cflag & CRTSCTS && !(modem & UARTMODIR_TXCTSE)) + lpuart32_write(port, modem | UARTMODIR_TXCTSE, UARTMODIR); + } lpuart32_write(port, temp, UARTCTRL); } From f57c2164d082a36d177ab7fbf54c18970df89c22 Mon Sep 17 00:00:00 2001 From: Isaac True Date: Wed, 30 Nov 2022 11:55:30 +0100 Subject: [PATCH 133/201] serial: sc16is7xx: setup GPIO controller later in probe [ Upstream commit c8f71b49ee4d28930c4a6798d1969fa91dc4ef3e ] The GPIO controller component of the sc16is7xx driver is setup too early, which can result in a race condition where another device tries to utilise the GPIO lines before the sc16is7xx device has finished initialising. This issue manifests itself as an Oops when the GPIO lines are configured: Unable to handle kernel read from unreadable memory at virtual address ... pc : sc16is7xx_gpio_direction_output+0x68/0x108 [sc16is7xx] lr : sc16is7xx_gpio_direction_output+0x4c/0x108 [sc16is7xx] ... Call trace: sc16is7xx_gpio_direction_output+0x68/0x108 [sc16is7xx] gpiod_direction_output_raw_commit+0x64/0x318 gpiod_direction_output+0xb0/0x170 create_gpio_led+0xec/0x198 gpio_led_probe+0x16c/0x4f0 platform_drv_probe+0x5c/0xb0 really_probe+0xe8/0x448 driver_probe_device+0xe8/0x138 __device_attach_driver+0x94/0x118 bus_for_each_drv+0x8c/0xe0 __device_attach+0x100/0x1b8 device_initial_probe+0x28/0x38 bus_probe_device+0xa4/0xb0 deferred_probe_work_func+0x90/0xe0 process_one_work+0x1c4/0x480 worker_thread+0x54/0x430 kthread+0x138/0x150 ret_from_fork+0x10/0x1c This patch moves the setup of the GPIO controller functions to later in the probe function, ensuring the sc16is7xx device has already finished initialising by the time other devices try to make use of the GPIO lines. The error handling has also been reordered to reflect the new initialisation order. Co-developed-by: Wen-chien Jesse Sung Signed-off-by: Wen-chien Jesse Sung Signed-off-by: Isaac True Link: https://lore.kernel.org/r/20221130105529.698385-1-isaac.true@canonical.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/tty/serial/sc16is7xx.c | 51 +++++++++++++++++----------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 524921360ca7..93cf5f788817 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1426,25 +1426,6 @@ static int sc16is7xx_probe(struct device *dev, } sched_set_fifo(s->kworker_task); -#ifdef CONFIG_GPIOLIB - if (devtype->nr_gpio) { - /* Setup GPIO cotroller */ - s->gpio.owner = THIS_MODULE; - s->gpio.parent = dev; - s->gpio.label = dev_name(dev); - s->gpio.direction_input = sc16is7xx_gpio_direction_input; - s->gpio.get = sc16is7xx_gpio_get; - s->gpio.direction_output = sc16is7xx_gpio_direction_output; - s->gpio.set = sc16is7xx_gpio_set; - s->gpio.base = -1; - s->gpio.ngpio = devtype->nr_gpio; - s->gpio.can_sleep = 1; - ret = gpiochip_add_data(&s->gpio, s); - if (ret) - goto out_thread; - } -#endif - /* reset device, purging any pending irq / data */ regmap_write(s->regmap, SC16IS7XX_IOCONTROL_REG << SC16IS7XX_REG_SHIFT, SC16IS7XX_IOCONTROL_SRESET_BIT); @@ -1521,6 +1502,25 @@ static int sc16is7xx_probe(struct device *dev, s->p[u].irda_mode = true; } +#ifdef CONFIG_GPIOLIB + if (devtype->nr_gpio) { + /* Setup GPIO cotroller */ + s->gpio.owner = THIS_MODULE; + s->gpio.parent = dev; + s->gpio.label = dev_name(dev); + s->gpio.direction_input = sc16is7xx_gpio_direction_input; + s->gpio.get = sc16is7xx_gpio_get; + s->gpio.direction_output = sc16is7xx_gpio_direction_output; + s->gpio.set = sc16is7xx_gpio_set; + s->gpio.base = -1; + s->gpio.ngpio = devtype->nr_gpio; + s->gpio.can_sleep = 1; + ret = gpiochip_add_data(&s->gpio, s); + if (ret) + goto out_thread; + } +#endif + /* * Setup interrupt. We first try to acquire the IRQ line as level IRQ. * If that succeeds, we can allow sharing the interrupt as well. @@ -1540,18 +1540,19 @@ static int sc16is7xx_probe(struct device *dev, if (!ret) return 0; -out_ports: - for (i--; i >= 0; i--) { - uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port); - clear_bit(s->p[i].port.line, &sc16is7xx_lines); - } - #ifdef CONFIG_GPIOLIB if (devtype->nr_gpio) gpiochip_remove(&s->gpio); out_thread: #endif + +out_ports: + for (i--; i >= 0; i--) { + uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port); + clear_bit(s->p[i].port.line, &sc16is7xx_lines); + } + kthread_stop(s->kworker_task); out_clk: From 947530c840449a16faaf17fba790462d3bce1791 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Mon, 12 Dec 2022 23:49:33 +0200 Subject: [PATCH 134/201] mei: bus-fixup:upon error print return values of send and receive [ Upstream commit 4b8659e2c258e4fdac9ccdf06cc20c0677894ef9 ] For easier debugging, upon error, print also return values from __mei_cl_recv() and __mei_cl_send() functions. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Link: https://lore.kernel.org/r/20221212214933.275434-1-tomas.winkler@intel.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/misc/mei/bus-fixup.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c index 71fbf0bc8453..5eeb4d04c096 100644 --- a/drivers/misc/mei/bus-fixup.c +++ b/drivers/misc/mei/bus-fixup.c @@ -151,7 +151,7 @@ static int mei_fwver(struct mei_cl_device *cldev) ret = __mei_cl_send(cldev->cl, (u8 *)&req, sizeof(req), 0, MEI_CL_IO_TX_BLOCKING); if (ret < 0) { - dev_err(&cldev->dev, "Could not send ReqFWVersion cmd\n"); + dev_err(&cldev->dev, "Could not send ReqFWVersion cmd ret = %d\n", ret); return ret; } @@ -163,7 +163,7 @@ static int mei_fwver(struct mei_cl_device *cldev) * Should be at least one version block, * error out if nothing found */ - dev_err(&cldev->dev, "Could not read FW version\n"); + dev_err(&cldev->dev, "Could not read FW version ret = %d\n", bytes_recv); return -EIO; } @@ -376,7 +376,7 @@ static int mei_nfc_if_version(struct mei_cl *cl, ret = __mei_cl_send(cl, (u8 *)&cmd, sizeof(cmd), 0, MEI_CL_IO_TX_BLOCKING); if (ret < 0) { - dev_err(bus->dev, "Could not send IF version cmd\n"); + dev_err(bus->dev, "Could not send IF version cmd ret = %d\n", ret); return ret; } @@ -391,7 +391,7 @@ static int mei_nfc_if_version(struct mei_cl *cl, bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length, &vtag, 0, 0); if (bytes_recv < 0 || (size_t)bytes_recv < if_version_length) { - dev_err(bus->dev, "Could not read IF version\n"); + dev_err(bus->dev, "Could not read IF version ret = %d\n", bytes_recv); ret = -EIO; goto err; } From 945877c145dd74505c61006bd7f4a12a37203b1d Mon Sep 17 00:00:00 2001 From: Yulong Zhang Date: Tue, 17 Jan 2023 10:51:47 +0800 Subject: [PATCH 135/201] tools/iio/iio_utils:fix memory leak [ Upstream commit f2edf0c819a4823cd6c288801ce737e8d4fcde06 ] 1. fopen sysfs without fclose. 2. asprintf filename without free. 3. if asprintf return error,do not need to free the buffer. Signed-off-by: Yulong Zhang Link: https://lore.kernel.org/r/20230117025147.69890-1-yulong.zhang@metoak.net Signed-off-by: Jonathan Cameron Signed-off-by: Sasha Levin --- tools/iio/iio_utils.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c index 8d35893b2fa8..6a00a6eecaef 100644 --- a/tools/iio/iio_utils.c +++ b/tools/iio/iio_utils.c @@ -264,6 +264,7 @@ int iioutils_get_param_float(float *output, const char *param_name, if (fscanf(sysfsfp, "%f", output) != 1) ret = errno ? -errno : -ENODATA; + fclose(sysfsfp); break; } error_free_filename: @@ -345,9 +346,9 @@ int build_channel_array(const char *device_dir, int buffer_idx, } sysfsfp = fopen(filename, "r"); + free(filename); if (!sysfsfp) { ret = -errno; - free(filename); goto error_close_dir; } @@ -357,7 +358,6 @@ int build_channel_array(const char *device_dir, int buffer_idx, if (fclose(sysfsfp)) perror("build_channel_array(): Failed to close file"); - free(filename); goto error_close_dir; } if (ret == 1) @@ -365,11 +365,9 @@ int build_channel_array(const char *device_dir, int buffer_idx, if (fclose(sysfsfp)) { ret = -errno; - free(filename); goto error_close_dir; } - free(filename); } *ci_array = malloc(sizeof(**ci_array) * (*counter)); @@ -395,9 +393,9 @@ int build_channel_array(const char *device_dir, int buffer_idx, } sysfsfp = fopen(filename, "r"); + free(filename); if (!sysfsfp) { ret = -errno; - free(filename); count--; goto error_cleanup_array; } @@ -405,20 +403,17 @@ int build_channel_array(const char *device_dir, int buffer_idx, errno = 0; if (fscanf(sysfsfp, "%i", ¤t_enabled) != 1) { ret = errno ? -errno : -ENODATA; - free(filename); count--; goto error_cleanup_array; } if (fclose(sysfsfp)) { ret = -errno; - free(filename); count--; goto error_cleanup_array; } if (!current_enabled) { - free(filename); count--; continue; } @@ -429,7 +424,6 @@ int build_channel_array(const char *device_dir, int buffer_idx, strlen(ent->d_name) - strlen("_en")); if (!current->name) { - free(filename); ret = -ENOMEM; count--; goto error_cleanup_array; @@ -439,7 +433,6 @@ int build_channel_array(const char *device_dir, int buffer_idx, ret = iioutils_break_up_name(current->name, ¤t->generic_name); if (ret) { - free(filename); free(current->name); count--; goto error_cleanup_array; @@ -450,17 +443,16 @@ int build_channel_array(const char *device_dir, int buffer_idx, scan_el_dir, current->name); if (ret < 0) { - free(filename); ret = -ENOMEM; goto error_cleanup_array; } sysfsfp = fopen(filename, "r"); + free(filename); if (!sysfsfp) { ret = -errno; - fprintf(stderr, "failed to open %s\n", - filename); - free(filename); + fprintf(stderr, "failed to open %s/%s_index\n", + scan_el_dir, current->name); goto error_cleanup_array; } @@ -470,17 +462,14 @@ int build_channel_array(const char *device_dir, int buffer_idx, if (fclose(sysfsfp)) perror("build_channel_array(): Failed to close file"); - free(filename); goto error_cleanup_array; } if (fclose(sysfsfp)) { ret = -errno; - free(filename); goto error_cleanup_array; } - free(filename); /* Find the scale */ ret = iioutils_get_param_float(¤t->scale, "scale", From 2d1716aba4621baab254d4fac499e90f99094b3f Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 28 Dec 2022 21:47:02 +0530 Subject: [PATCH 136/201] bus: mhi: ep: Fix the debug message for MHI_PKT_TYPE_RESET_CHAN_CMD cmd [ Upstream commit 8e697fcfdb9809634e268058ca743369c216b7ac ] The debug log incorrectly mentions that STOP command is received instead of RESET command. Fix that. Signed-off-by: Manivannan Sadhasivam Reviewed-by: Jeffrey Hugo Link: https://lore.kernel.org/r/20221228161704.255268-5-manivannan.sadhasivam@linaro.org Signed-off-by: Manivannan Sadhasivam Signed-off-by: Sasha Levin --- drivers/bus/mhi/ep/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bus/mhi/ep/main.c b/drivers/bus/mhi/ep/main.c index 9c4288681841..357c61c12ce5 100644 --- a/drivers/bus/mhi/ep/main.c +++ b/drivers/bus/mhi/ep/main.c @@ -219,7 +219,7 @@ static int mhi_ep_process_cmd_ring(struct mhi_ep_ring *ring, struct mhi_ring_ele mutex_unlock(&mhi_chan->lock); break; case MHI_PKT_TYPE_RESET_CHAN_CMD: - dev_dbg(dev, "Received STOP command for channel (%u)\n", ch_id); + dev_dbg(dev, "Received RESET command for channel (%u)\n", ch_id); if (!ch_ring->started) { dev_err(dev, "Channel (%u) not opened\n", ch_id); return -ENODEV; From be0c84d908077071702cedc3ab691398e5969a5b Mon Sep 17 00:00:00 2001 From: Harshit Mogalapalli Date: Thu, 26 Jan 2023 07:21:46 -0800 Subject: [PATCH 137/201] iio: accel: mma9551_core: Prevent uninitialized variable in mma9551_read_status_word() [ Upstream commit e56d2c34ce9dc122b1a618172ec0e05e50adb9e9 ] Smatch Warns: drivers/iio/accel/mma9551_core.c:357 mma9551_read_status_word() error: uninitialized symbol 'v'. When (offset >= 1 << 12) is true mma9551_transfer() will return -EINVAL without 'v' being initialized, so check for the error and return. Note: Not a bug as such because the caller checks return value and doesn't not use this parameter in the problem case. Signed-off-by: Harshit Mogalapalli Link: https://lore.kernel.org/r/20230126152147.3585874-1-harshit.m.mogalapalli@oracle.com Signed-off-by: Jonathan Cameron Signed-off-by: Sasha Levin --- drivers/iio/accel/mma9551_core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c index 64ca7d7a9673..86437ddc5ca1 100644 --- a/drivers/iio/accel/mma9551_core.c +++ b/drivers/iio/accel/mma9551_core.c @@ -354,9 +354,12 @@ int mma9551_read_status_word(struct i2c_client *client, u8 app_id, ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS, reg, NULL, 0, (u8 *)&v, 2); + if (ret < 0) + return ret; + *val = be16_to_cpu(v); - return ret; + return 0; } EXPORT_SYMBOL_NS(mma9551_read_status_word, IIO_MMA9551); From f5a2a15da3bcf5561f2141c357616885c023331c Mon Sep 17 00:00:00 2001 From: Harshit Mogalapalli Date: Thu, 26 Jan 2023 07:36:09 -0800 Subject: [PATCH 138/201] iio: accel: mma9551_core: Prevent uninitialized variable in mma9551_read_config_word() [ Upstream commit 64a68158738ec8f520347144352f7a09bdb9e169 ] Smatch Warns: drivers/iio/accel/mma9551_core.c:299 mma9551_read_config_word() error: uninitialized symbol 'v'. When (offset >= 1 << 12) is true mma9551_transfer() will return -EINVAL without 'v' being initialized, so check for the error and return. Note: No actual bug as caller checks the return value and does not use the parameter in the problem case. Signed-off-by: Harshit Mogalapalli Link: https://lore.kernel.org/r/20230126153610.3586243-1-harshit.m.mogalapalli@oracle.com Signed-off-by: Jonathan Cameron Signed-off-by: Sasha Levin --- drivers/iio/accel/mma9551_core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c index 86437ddc5ca1..b898f865fb87 100644 --- a/drivers/iio/accel/mma9551_core.c +++ b/drivers/iio/accel/mma9551_core.c @@ -296,9 +296,12 @@ int mma9551_read_config_word(struct i2c_client *client, u8 app_id, ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG, reg, NULL, 0, (u8 *)&v, 2); + if (ret < 0) + return ret; + *val = be16_to_cpu(v); - return ret; + return 0; } EXPORT_SYMBOL_NS(mma9551_read_config_word, IIO_MMA9551); From 638eeb0e8ade0cd63d1e35d05fce8099867115dc Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 27 Jan 2023 00:14:52 +0100 Subject: [PATCH 139/201] media: uvcvideo: Add GUID for BGRA/X 8:8:8:8 [ Upstream commit 015d44c2b700ba9639dd29672ba362796cc0be54 ] The Cypress EZUSB FX3 UVC example can be configured to report pixel format "e436eb7e-524f-11ce-9f53-0020af0ba770". This is its GUID for BGRA/X 8:8:8:8. The UVC 1.5 spec [1] only defines GUIDs for YUY2, NV12, M420 and I420. This seems to be an extension documented in the Microsoft Windows Media Format SDK[2]. This Media Format SDK defines this GUID as corresponding to `MEDIASUBTYPE_RGB32`, which is confirmed by [4] as `MEDIASUBTYPE_ARGB32` has different GUID. Note that in my case, the FX3 UVC can output either channel order, BGR or RGB or any other mix for that matter. Since Linux commit 1b8dc32286a1a ("[media] uvcvideo: Add GUID for BGR 8:8:8") defined a GUID for `MEDIASUBTYPE_RGB24` channel order as BGR, keep this change consistent and define `MEDIASUBTYPE_RGB32` as BGR as well. Document [3] also indicates the channel order is BGR. [1] https://www.usb.org/document-library/video-class-v15-document-set [2] https://learn.microsoft.com/en-us/windows/win32/wmformat/media-type-identifiers [3] https://learn.microsoft.com/en-us/windows/win32/directshow/uncompressed-rgb-video-subtypes [4] https://gix.github.io/media-types/ Signed-off-by: Marek Vasut Reviewed-by: Laurent Pinchart Reviewed-by: Ricardo Ribalda Signed-off-by: Michael Grzeschik Link: https://lore.kernel.org/r/20230126231456.3402323-2-m.grzeschik@pengutronix.de Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- include/media/v4l2-uvc.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/media/v4l2-uvc.h b/include/media/v4l2-uvc.h index f83e31661333..b010a36fc1d9 100644 --- a/include/media/v4l2-uvc.h +++ b/include/media/v4l2-uvc.h @@ -99,6 +99,9 @@ #define UVC_GUID_FORMAT_BGR3 \ { 0x7d, 0xeb, 0x36, 0xe4, 0x4f, 0x52, 0xce, 0x11, \ 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70} +#define UVC_GUID_FORMAT_BGR4 \ + { 0x7e, 0xeb, 0x36, 0xe4, 0x4f, 0x52, 0xce, 0x11, \ + 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70} #define UVC_GUID_FORMAT_M420 \ { 'M', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} @@ -266,6 +269,11 @@ static struct uvc_format_desc uvc_fmts[] = { .guid = UVC_GUID_FORMAT_BGR3, .fcc = V4L2_PIX_FMT_BGR24, }, + { + .name = "BGRA/X 8:8:8:8 (BGR4)", + .guid = UVC_GUID_FORMAT_BGR4, + .fcc = V4L2_PIX_FMT_XBGR32, + }, { .name = "H.264", .guid = UVC_GUID_FORMAT_H264, From bace2a37de7c1feb0e4b6f34a3ff8ed29884fa7e Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 23 Jan 2023 17:25:20 +0000 Subject: [PATCH 140/201] soundwire: bus_type: Avoid lockdep assert in sdw_drv_probe() [ Upstream commit 3dca1f89ae3455963d7b53245ecf298ea9bae857 ] Don't hold sdw_dev_lock while calling the peripheral driver probe() and remove() callbacks. Holding sdw_dev_lock around the probe() and remove() calls causes a theoretical mutex inversion which lockdep will assert on. During probe() the sdw_dev_lock mutex is taken first and then ASoC/ALSA locks are taken by the probe() implementation. During normal operation ASoC can take its locks and then trigger a runtime resume of the component. The SoundWire resume will then take sdw_dev_lock. This is the reverse order compared to probe(). It's not necessary to hold sdw_dev_lock when calling the probe() and remove(), it is only used to prevent the bus core calling the driver callbacks if there isn't a driver or the driver is removing. All calls to the driver callbacks are guarded by the 'probed' flag. So if sdw_dev_lock is held while setting and clearing the 'probed' flag this is sufficient to guarantee the safety of callback functions. Removing the mutex from around the call to probe() means that it is now possible for a bus event (PING response) to be handled in parallel with the probe(). But sdw_bus_probe() already has handling for this by calling the device update_status() after the probe() has completed. Example lockdep assert: [ 46.098514] ====================================================== [ 46.104736] WARNING: possible circular locking dependency detected [ 46.110961] 6.1.0-rc4-jamerson #1 Tainted: G E [ 46.116842] ------------------------------------------------------ [ 46.123063] mpg123/1130 is trying to acquire lock: [ 46.127883] ffff8b445031fb80 (&slave->sdw_dev_lock){+.+.}-{3:3}, at: sdw_update_slave_status+0x26/0x70 [ 46.137225] but task is already holding lock: [ 46.143074] ffffffffc1455310 (&card->pcm_mutex){+.+.}-{3:3}, at: dpcm_fe_dai_open+0x49/0x830 [ 46.151536] which lock already depends on the new lock.[ 46.159732] the existing dependency chain (in reverse order) is: [ 46.167231] -> #4 (&card->pcm_mutex){+.+.}-{3:3}: [ 46.173428] __mutex_lock+0x94/0x920 [ 46.177542] snd_soc_dpcm_runtime_update+0x2e/0x100 [ 46.182958] snd_soc_dapm_put_enum_double+0x1c2/0x200 [ 46.188548] snd_ctl_elem_write+0x10c/0x1d0 [ 46.193268] snd_ctl_ioctl+0x126/0x850 [ 46.197556] __x64_sys_ioctl+0x87/0xc0 [ 46.201845] do_syscall_64+0x38/0x90 [ 46.205959] entry_SYSCALL_64_after_hwframe+0x63/0xcd [ 46.211553] -> #3 (&card->controls_rwsem){++++}-{3:3}: [ 46.218188] down_write+0x2b/0xd0 [ 46.222038] snd_ctl_add_replace+0x39/0xb0 [ 46.226672] snd_soc_add_controls+0x53/0x80 [ 46.231393] soc_probe_component+0x1e4/0x2a0 [ 46.236202] snd_soc_bind_card+0x51a/0xc80 [ 46.240836] devm_snd_soc_register_card+0x43/0x90 [ 46.246079] mc_probe+0x982/0xfe0 [snd_soc_sof_sdw] [ 46.251500] platform_probe+0x3c/0xa0 [ 46.255700] really_probe+0xde/0x390 [ 46.259814] __driver_probe_device+0x78/0x180 [ 46.264710] driver_probe_device+0x1e/0x90 [ 46.269347] __driver_attach+0x9f/0x1f0 [ 46.273721] bus_for_each_dev+0x78/0xc0 [ 46.278098] bus_add_driver+0x1ac/0x200 [ 46.282473] driver_register+0x8f/0xf0 [ 46.286759] do_one_initcall+0x58/0x310 [ 46.291136] do_init_module+0x4c/0x1f0 [ 46.295422] __do_sys_finit_module+0xb4/0x130 [ 46.300321] do_syscall_64+0x38/0x90 [ 46.304434] entry_SYSCALL_64_after_hwframe+0x63/0xcd [ 46.310027] -> #2 (&card->mutex){+.+.}-{3:3}: [ 46.315883] __mutex_lock+0x94/0x920 [ 46.320000] snd_soc_bind_card+0x3e/0xc80 [ 46.324551] devm_snd_soc_register_card+0x43/0x90 [ 46.329798] mc_probe+0x982/0xfe0 [snd_soc_sof_sdw] [ 46.335219] platform_probe+0x3c/0xa0 [ 46.339420] really_probe+0xde/0x390 [ 46.343532] __driver_probe_device+0x78/0x180 [ 46.348430] driver_probe_device+0x1e/0x90 [ 46.353065] __driver_attach+0x9f/0x1f0 [ 46.357437] bus_for_each_dev+0x78/0xc0 [ 46.361812] bus_add_driver+0x1ac/0x200 [ 46.366716] driver_register+0x8f/0xf0 [ 46.371528] do_one_initcall+0x58/0x310 [ 46.376424] do_init_module+0x4c/0x1f0 [ 46.381239] __do_sys_finit_module+0xb4/0x130 [ 46.386665] do_syscall_64+0x38/0x90 [ 46.391299] entry_SYSCALL_64_after_hwframe+0x63/0xcd [ 46.397416] -> #1 (client_mutex){+.+.}-{3:3}: [ 46.404307] __mutex_lock+0x94/0x920 [ 46.408941] snd_soc_add_component+0x24/0x2c0 [ 46.414345] devm_snd_soc_register_component+0x54/0xa0 [ 46.420522] cs35l56_common_probe+0x280/0x370 [snd_soc_cs35l56] [ 46.427487] cs35l56_sdw_probe+0xf4/0x170 [snd_soc_cs35l56_sdw] [ 46.434442] sdw_drv_probe+0x80/0x1a0 [ 46.439136] really_probe+0xde/0x390 [ 46.443738] __driver_probe_device+0x78/0x180 [ 46.449120] driver_probe_device+0x1e/0x90 [ 46.454247] __driver_attach+0x9f/0x1f0 [ 46.459106] bus_for_each_dev+0x78/0xc0 [ 46.463971] bus_add_driver+0x1ac/0x200 [ 46.468825] driver_register+0x8f/0xf0 [ 46.473592] do_one_initcall+0x58/0x310 [ 46.478441] do_init_module+0x4c/0x1f0 [ 46.483202] __do_sys_finit_module+0xb4/0x130 [ 46.488572] do_syscall_64+0x38/0x90 [ 46.493158] entry_SYSCALL_64_after_hwframe+0x63/0xcd [ 46.499229] -> #0 (&slave->sdw_dev_lock){+.+.}-{3:3}: [ 46.506737] __lock_acquire+0x1121/0x1df0 [ 46.511765] lock_acquire+0xd5/0x300 [ 46.516360] __mutex_lock+0x94/0x920 [ 46.520949] sdw_update_slave_status+0x26/0x70 [ 46.526409] sdw_clear_slave_status+0xd8/0xe0 [ 46.531783] intel_resume_runtime+0x139/0x2a0 [ 46.537155] __rpm_callback+0x41/0x120 [ 46.541919] rpm_callback+0x5d/0x70 [ 46.546422] rpm_resume+0x531/0x7e0 [ 46.550920] __pm_runtime_resume+0x4a/0x80 [ 46.556024] snd_soc_pcm_component_pm_runtime_get+0x2f/0xc0 [ 46.562611] __soc_pcm_open+0x62/0x520 [ 46.567375] dpcm_be_dai_startup+0x116/0x210 [ 46.572661] dpcm_fe_dai_open+0xf7/0x830 [ 46.577597] snd_pcm_open_substream+0x54a/0x8b0 [ 46.583145] snd_pcm_open.part.0+0xdc/0x200 [ 46.588341] snd_pcm_playback_open+0x51/0x80 [ 46.593625] chrdev_open+0xc0/0x250 [ 46.598129] do_dentry_open+0x15f/0x430 [ 46.602981] path_openat+0x75e/0xa80 [ 46.607575] do_filp_open+0xb2/0x160 [ 46.612162] do_sys_openat2+0x9a/0x160 [ 46.616922] __x64_sys_openat+0x53/0xa0 [ 46.621767] do_syscall_64+0x38/0x90 [ 46.626352] entry_SYSCALL_64_after_hwframe+0x63/0xcd [ 46.632414] other info that might help us debug this:[ 46.641862] Chain exists of: &slave->sdw_dev_lock --> &card->controls_rwsem --> &card->pcm_mutex[ 46.655145] Possible unsafe locking scenario:[ 46.662048] CPU0 CPU1 [ 46.667080] ---- ---- [ 46.672108] lock(&card->pcm_mutex); [ 46.676267] lock(&card->controls_rwsem); [ 46.683382] lock(&card->pcm_mutex); [ 46.690063] lock(&slave->sdw_dev_lock); [ 46.694574] *** DEADLOCK ***[ 46.701942] 2 locks held by mpg123/1130: [ 46.706356] #0: ffff8b4457b22b90 (&pcm->open_mutex){+.+.}-{3:3}, at: snd_pcm_open.part.0+0xc9/0x200 [ 46.715999] #1: ffffffffc1455310 (&card->pcm_mutex){+.+.}-{3:3}, at: dpcm_fe_dai_open+0x49/0x830 [ 46.725390] stack backtrace: [ 46.730752] CPU: 0 PID: 1130 Comm: mpg123 Tainted: G E 6.1.0-rc4-jamerson #1 [ 46.739703] Hardware name: AAEON UP-WHL01/UP-WHL01, BIOS UPW1AM19 11/10/2020 [ 46.747270] Call Trace: [ 46.750239] [ 46.752857] dump_stack_lvl+0x56/0x73 [ 46.757045] check_noncircular+0x102/0x120 [ 46.761664] __lock_acquire+0x1121/0x1df0 [ 46.766197] lock_acquire+0xd5/0x300 [ 46.770292] ? sdw_update_slave_status+0x26/0x70 [ 46.775432] ? lock_is_held_type+0xe2/0x140 [ 46.780143] __mutex_lock+0x94/0x920 [ 46.784241] ? sdw_update_slave_status+0x26/0x70 [ 46.789387] ? find_held_lock+0x2b/0x80 [ 46.793750] ? sdw_update_slave_status+0x26/0x70 [ 46.798894] ? lock_release+0x147/0x2f0 [ 46.803262] ? lockdep_init_map_type+0x47/0x250 [ 46.808315] ? sdw_update_slave_status+0x26/0x70 [ 46.813456] sdw_update_slave_status+0x26/0x70 [ 46.818422] sdw_clear_slave_status+0xd8/0xe0 [ 46.823302] ? pm_generic_runtime_suspend+0x30/0x30 [ 46.828706] intel_resume_runtime+0x139/0x2a0 [ 46.833583] ? _raw_spin_unlock_irq+0x24/0x50 [ 46.838462] ? pm_generic_runtime_suspend+0x30/0x30 [ 46.843866] __rpm_callback+0x41/0x120 [ 46.848142] ? pm_generic_runtime_suspend+0x30/0x30 [ 46.853550] rpm_callback+0x5d/0x70 [ 46.857568] rpm_resume+0x531/0x7e0 [ 46.861578] ? _raw_spin_lock_irqsave+0x62/0x70 [ 46.866634] __pm_runtime_resume+0x4a/0x80 [ 46.871258] snd_soc_pcm_component_pm_runtime_get+0x2f/0xc0 [ 46.877358] __soc_pcm_open+0x62/0x520 [ 46.881634] ? dpcm_add_paths.isra.0+0x35d/0x4c0 [ 46.886784] dpcm_be_dai_startup+0x116/0x210 [ 46.891592] dpcm_fe_dai_open+0xf7/0x830 [ 46.896046] ? debug_mutex_init+0x33/0x50 [ 46.900591] snd_pcm_open_substream+0x54a/0x8b0 [ 46.905658] snd_pcm_open.part.0+0xdc/0x200 [ 46.910376] ? wake_up_q+0x90/0x90 [ 46.914312] snd_pcm_playback_open+0x51/0x80 [ 46.919118] chrdev_open+0xc0/0x250 [ 46.923147] ? cdev_device_add+0x90/0x90 [ 46.927608] do_dentry_open+0x15f/0x430 [ 46.931976] path_openat+0x75e/0xa80 [ 46.936086] do_filp_open+0xb2/0x160 [ 46.940194] ? lock_release+0x147/0x2f0 [ 46.944563] ? _raw_spin_unlock+0x29/0x50 [ 46.949101] do_sys_openat2+0x9a/0x160 [ 46.953377] __x64_sys_openat+0x53/0xa0 [ 46.957733] do_syscall_64+0x38/0x90 [ 46.961829] entry_SYSCALL_64_after_hwframe+0x63/0xcd [ 46.967402] RIP: 0033:0x7fa6397ccd3b [ 46.971506] Code: 25 00 00 41 00 3d 00 00 41 00 74 4b 64 8b 04 25 18 00 00 00 85 c0 75 67 44 89 e2 48 89 ee bf 9c ff ff ff b8 01 01 00 00 0f 05 <48> 3d 00 f0 ff ff 0f 87 91 00 00 00 48 8b 4c 24 28 64 48 33 0c 25 [ 46.991413] RSP: 002b:00007fff838e8990 EFLAGS: 00000246 ORIG_RAX: 0000000000000101 [ 46.999580] RAX: ffffffffffffffda RBX: 0000000000080802 RCX: 00007fa6397ccd3b [ 47.007311] RDX: 0000000000080802 RSI: 00007fff838e8b50 RDI: 00000000ffffff9c [ 47.015047] RBP: 00007fff838e8b50 R08: 0000000000000000 R09: 0000000000000011 [ 47.022787] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000080802 [ 47.030539] R13: 0000000000000004 R14: 0000000000000000 R15: 00007fff838e8b50 [ 47.038289] Signed-off-by: Richard Fitzgerald Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20230123172520.339367-1-rf@opensource.cirrus.com Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/soundwire/bus_type.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index 04b3529f8929..963498db0fd2 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -105,20 +105,19 @@ static int sdw_drv_probe(struct device *dev) if (ret) return ret; - mutex_lock(&slave->sdw_dev_lock); - ret = drv->probe(slave, id); if (ret) { name = drv->name; if (!name) name = drv->driver.name; - mutex_unlock(&slave->sdw_dev_lock); dev_err(dev, "Probe of %s failed: %d\n", name, ret); dev_pm_domain_detach(dev, false); return ret; } + mutex_lock(&slave->sdw_dev_lock); + /* device is probed so let's read the properties now */ if (drv->ops && drv->ops->read_prop) drv->ops->read_prop(slave); @@ -167,14 +166,12 @@ static int sdw_drv_remove(struct device *dev) int ret = 0; mutex_lock(&slave->sdw_dev_lock); - slave->probed = false; + mutex_unlock(&slave->sdw_dev_lock); if (drv->remove) ret = drv->remove(slave); - mutex_unlock(&slave->sdw_dev_lock); - dev_pm_domain_detach(dev, false); return ret; From d8c911d3d879db7c16a817323aef3035ee2eb774 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Wed, 1 Feb 2023 12:30:18 +0800 Subject: [PATCH 141/201] PCI: loongson: Prevent LS7A MRRS increases [ Upstream commit 8b3517f88ff2983f52698893519227c10aac90b2 ] Except for isochronous-configured devices, software may set Max_Read_Request_Size (MRRS) to any value up to 4096. If a device issues a read request with size greater than the completer's Max_Payload_Size (MPS), the completer is required to break the response into multiple completions. Instead of correctly responding with multiple completions to a large read request, some LS7A Root Ports respond with a Completer Abort. To prevent this, the MRRS must be limited to an implementation-specific value. The OS cannot detect that value, so rely on BIOS to configure MRRS before booting, and quirk the Root Ports so we never set an MRRS larger than that BIOS value for any downstream device. N.B. Hot-added devices are not configured by BIOS, and they power up with MRRS = 512 bytes, so these devices will be limited to 512 bytes. If the LS7A limit is smaller, those hot-added devices may not work correctly, but per [1], hotplug is not supported with this chipset revision. [1] https://lore.kernel.org/r/073638a7-ae68-2847-ac3d-29e5e760d6af@loongson.cn [bhelgaas: commit log] Link: https://bugzilla.kernel.org/show_bug.cgi?id=216884 Link: https://lore.kernel.org/r/20230201043018.778499-3-chenhuacai@loongson.cn Signed-off-by: Huacai Chen Signed-off-by: Bjorn Helgaas Signed-off-by: Sasha Levin --- drivers/pci/controller/pci-loongson.c | 42 +++++++++------------------ drivers/pci/pci.c | 10 +++++++ include/linux/pci.h | 1 + 3 files changed, 25 insertions(+), 28 deletions(-) diff --git a/drivers/pci/controller/pci-loongson.c b/drivers/pci/controller/pci-loongson.c index 05c50408f13b..759ec211c17b 100644 --- a/drivers/pci/controller/pci-loongson.c +++ b/drivers/pci/controller/pci-loongson.c @@ -75,37 +75,23 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, DEV_LS7A_LPC, system_bus_quirk); -static void loongson_mrrs_quirk(struct pci_dev *dev) +static void loongson_mrrs_quirk(struct pci_dev *pdev) { - struct pci_bus *bus = dev->bus; - struct pci_dev *bridge; - static const struct pci_device_id bridge_devids[] = { - { PCI_VDEVICE(LOONGSON, DEV_PCIE_PORT_0) }, - { PCI_VDEVICE(LOONGSON, DEV_PCIE_PORT_1) }, - { PCI_VDEVICE(LOONGSON, DEV_PCIE_PORT_2) }, - { 0, }, - }; + /* + * Some Loongson PCIe ports have h/w limitations of maximum read + * request size. They can't handle anything larger than this. So + * force this limit on any devices attached under these ports. + */ + struct pci_host_bridge *bridge = pci_find_host_bridge(pdev->bus); - /* look for the matching bridge */ - while (!pci_is_root_bus(bus)) { - bridge = bus->self; - bus = bus->parent; - /* - * Some Loongson PCIe ports have a h/w limitation of - * 256 bytes maximum read request size. They can't handle - * anything larger than this. So force this limit on - * any devices attached under these ports. - */ - if (pci_match_id(bridge_devids, bridge)) { - if (pcie_get_readrq(dev) > 256) { - pci_info(dev, "limiting MRRS to 256\n"); - pcie_set_readrq(dev, 256); - } - break; - } - } + bridge->no_inc_mrrs = 1; } -DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, loongson_mrrs_quirk); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, + DEV_PCIE_PORT_0, loongson_mrrs_quirk); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, + DEV_PCIE_PORT_1, loongson_mrrs_quirk); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, + DEV_PCIE_PORT_2, loongson_mrrs_quirk); static void loongson_pci_pin_quirk(struct pci_dev *pdev) { diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index c20e95fd48ce..98d841a7b45b 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -6017,6 +6017,7 @@ int pcie_set_readrq(struct pci_dev *dev, int rq) { u16 v; int ret; + struct pci_host_bridge *bridge = pci_find_host_bridge(dev->bus); if (rq < 128 || rq > 4096 || !is_power_of_2(rq)) return -EINVAL; @@ -6035,6 +6036,15 @@ int pcie_set_readrq(struct pci_dev *dev, int rq) v = (ffs(rq) - 8) << 12; + if (bridge->no_inc_mrrs) { + int max_mrrs = pcie_get_readrq(dev); + + if (rq > max_mrrs) { + pci_info(dev, "can't set Max_Read_Request_Size to %d; max is %d\n", rq, max_mrrs); + return -EINVAL; + } + } + ret = pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_READRQ, v); diff --git a/include/linux/pci.h b/include/linux/pci.h index 2bda4a4e47e8..cb538bc57971 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -570,6 +570,7 @@ struct pci_host_bridge { void *release_data; unsigned int ignore_reset_delay:1; /* For entire hierarchy */ unsigned int no_ext_tags:1; /* No Extended Tags */ + unsigned int no_inc_mrrs:1; /* No Increase MRRS */ unsigned int native_aer:1; /* OS may use PCIe AER */ unsigned int native_pcie_hotplug:1; /* OS may use PCIe hotplug */ unsigned int native_shpc_hotplug:1; /* OS may use SHPC hotplug */ From 04f3cda40e9f6653ae15ed3fcf26ef2860f4df66 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Feb 2023 15:11:38 +0100 Subject: [PATCH 142/201] staging: pi433: fix memory leak with using debugfs_lookup() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 2f36e789e540df6a9fbf471b3a2ba62a8b361586 ] When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once. This requires saving off the root directory dentry to make creation of individual device subdirectories easier. Cc: Paulo Miguel Almeida Cc: Dan Carpenter Cc: Sidong Yang Cc: Liu Shixin Cc: "Uwe Kleine-König" Link: https://lore.kernel.org/r/20230202141138.2291946-1-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/staging/pi433/pi433_if.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c index d4e06a3929f3..b59f6a4cb611 100644 --- a/drivers/staging/pi433/pi433_if.c +++ b/drivers/staging/pi433/pi433_if.c @@ -55,6 +55,7 @@ static dev_t pi433_dev; static DEFINE_IDR(pi433_idr); static DEFINE_MUTEX(minor_lock); /* Protect idr accesses */ +static struct dentry *root_dir; /* debugfs root directory for the driver */ static struct class *pi433_class; /* mainly for udev to create /dev/pi433 */ @@ -1306,8 +1307,7 @@ static int pi433_probe(struct spi_device *spi) /* spi setup */ spi_set_drvdata(spi, device); - entry = debugfs_create_dir(dev_name(device->dev), - debugfs_lookup(KBUILD_MODNAME, NULL)); + entry = debugfs_create_dir(dev_name(device->dev), root_dir); debugfs_create_file("regs", 0400, entry, device, &pi433_debugfs_regs_fops); return 0; @@ -1333,9 +1333,8 @@ RX_failed: static void pi433_remove(struct spi_device *spi) { struct pi433_device *device = spi_get_drvdata(spi); - struct dentry *mod_entry = debugfs_lookup(KBUILD_MODNAME, NULL); - debugfs_remove(debugfs_lookup(dev_name(device->dev), mod_entry)); + debugfs_lookup_and_remove(dev_name(device->dev), root_dir); /* free GPIOs */ free_gpio(device); @@ -1408,7 +1407,7 @@ static int __init pi433_init(void) return PTR_ERR(pi433_class); } - debugfs_create_dir(KBUILD_MODNAME, NULL); + root_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); status = spi_register_driver(&pi433_spi_driver); if (status < 0) { @@ -1427,7 +1426,7 @@ static void __exit pi433_exit(void) spi_unregister_driver(&pi433_spi_driver); class_destroy(pi433_class); unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name); - debugfs_remove_recursive(debugfs_lookup(KBUILD_MODNAME, NULL)); + debugfs_remove(root_dir); } module_exit(pi433_exit); From ce234af49d103d95e3fdca59b25e0d0242f41bb4 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Feb 2023 16:28:20 +0100 Subject: [PATCH 143/201] USB: dwc3: fix memory leak with using debugfs_lookup() [ Upstream commit be308d68785b205e483b3a0c61ba3a82da468f2c ] When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once. Note, the root dentry for the debugfs directory for the device needs to be saved so we don't have to keep looking it up, which required a bit more refactoring to properly create and remove it when needed. Reported-by: Bruce Chen Reported-by: Cixi Geng Tested-by: Cixi Geng Acked-by: Thinh Nguyen Link: https://lore.kernel.org/r/20230202152820.2409908-1-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/dwc3/core.h | 2 ++ drivers/usb/dwc3/debug.h | 3 +++ drivers/usb/dwc3/debugfs.c | 19 ++++++++----------- drivers/usb/dwc3/gadget.c | 4 +--- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 8f9959ba9fd4..582ebd9cf9c2 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1117,6 +1117,7 @@ struct dwc3_scratchpad_array { * address. * @num_ep_resized: carries the current number endpoints which have had its tx * fifo resized. + * @debug_root: root debugfs directory for this device to put its files in. */ struct dwc3 { struct work_struct drd_work; @@ -1332,6 +1333,7 @@ struct dwc3 { int max_cfg_eps; int last_fifo_depth; int num_ep_resized; + struct dentry *debug_root; }; #define INCRX_BURST_MODE 0 diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index 48b44b88dc25..8bb2c9e3b9ac 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h @@ -414,11 +414,14 @@ static inline const char *dwc3_gadget_generic_cmd_status_string(int status) #ifdef CONFIG_DEBUG_FS extern void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep); +extern void dwc3_debugfs_remove_endpoint_dir(struct dwc3_ep *dep); extern void dwc3_debugfs_init(struct dwc3 *d); extern void dwc3_debugfs_exit(struct dwc3 *d); #else static inline void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep) { } +static inline void dwc3_debugfs_remove_endpoint_dir(struct dwc3_ep *dep) +{ } static inline void dwc3_debugfs_init(struct dwc3 *d) { } static inline void dwc3_debugfs_exit(struct dwc3 *d) diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index f2b7675c7f62..850df0e6bcab 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -873,27 +873,23 @@ static const struct dwc3_ep_file_map dwc3_ep_file_map[] = { { "GDBGEPINFO", &dwc3_ep_info_register_fops, }, }; -static void dwc3_debugfs_create_endpoint_files(struct dwc3_ep *dep, - struct dentry *parent) +void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep) { + struct dentry *dir; int i; + dir = debugfs_create_dir(dep->name, dep->dwc->debug_root); for (i = 0; i < ARRAY_SIZE(dwc3_ep_file_map); i++) { const struct file_operations *fops = dwc3_ep_file_map[i].fops; const char *name = dwc3_ep_file_map[i].name; - debugfs_create_file(name, 0444, parent, dep, fops); + debugfs_create_file(name, 0444, dir, dep, fops); } } -void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep) +void dwc3_debugfs_remove_endpoint_dir(struct dwc3_ep *dep) { - struct dentry *dir; - struct dentry *root; - - root = debugfs_lookup(dev_name(dep->dwc->dev), usb_debug_root); - dir = debugfs_create_dir(dep->name, root); - dwc3_debugfs_create_endpoint_files(dep, dir); + debugfs_lookup_and_remove(dep->name, dep->dwc->debug_root); } void dwc3_debugfs_init(struct dwc3 *dwc) @@ -911,6 +907,7 @@ void dwc3_debugfs_init(struct dwc3 *dwc) dwc->regset->base = dwc->regs - DWC3_GLOBALS_REGS_START; root = debugfs_create_dir(dev_name(dwc->dev), usb_debug_root); + dwc->debug_root = root; debugfs_create_regset32("regdump", 0444, root, dwc->regset); debugfs_create_file("lsp_dump", 0644, root, dwc, &dwc3_lsp_fops); @@ -929,6 +926,6 @@ void dwc3_debugfs_init(struct dwc3 *dwc) void dwc3_debugfs_exit(struct dwc3 *dwc) { - debugfs_remove(debugfs_lookup(dev_name(dwc->dev), usb_debug_root)); + debugfs_lookup_and_remove(dev_name(dwc->dev), usb_debug_root); kfree(dwc->regset); } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index ed958da0e1c9..df1ce96fa228 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -3184,9 +3184,7 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc) list_del(&dep->endpoint.ep_list); } - debugfs_remove_recursive(debugfs_lookup(dep->name, - debugfs_lookup(dev_name(dep->dwc->dev), - usb_debug_root))); + dwc3_debugfs_remove_endpoint_dir(dep); kfree(dep); } } From 610373dd354f3d393aa3bdcab59f55024c16b5e5 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Feb 2023 16:32:23 +0100 Subject: [PATCH 144/201] USB: chipidea: fix memory leak with using debugfs_lookup() [ Upstream commit ff35f3ea3baba5b81416ac02d005cfbf6dd182fa ] When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once. Cc: Peter Chen Link: https://lore.kernel.org/r/20230202153235.2412790-1-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/chipidea/debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index faf6b078b6c4..bbc610e5bd69 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -364,5 +364,5 @@ void dbg_create_files(struct ci_hdrc *ci) */ void dbg_remove_files(struct ci_hdrc *ci) { - debugfs_remove(debugfs_lookup(dev_name(ci->dev), usb_debug_root)); + debugfs_lookup_and_remove(dev_name(ci->dev), usb_debug_root); } From dcbe69f4f743a938344b32e60531ea55355e0c08 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Feb 2023 16:32:24 +0100 Subject: [PATCH 145/201] USB: ULPI: fix memory leak with using debugfs_lookup() [ Upstream commit 8f4d25eba599c4bd4b5ea8ae8752cda480a9d563 ] When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once. Acked-by: Heikki Krogerus Link: https://lore.kernel.org/r/20230202153235.2412790-2-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/common/ulpi.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c index d7c8461976ce..38703781ee2d 100644 --- a/drivers/usb/common/ulpi.c +++ b/drivers/usb/common/ulpi.c @@ -271,7 +271,7 @@ static int ulpi_regs_show(struct seq_file *seq, void *data) } DEFINE_SHOW_ATTRIBUTE(ulpi_regs); -#define ULPI_ROOT debugfs_lookup(KBUILD_MODNAME, NULL) +static struct dentry *ulpi_root; static int ulpi_register(struct device *dev, struct ulpi *ulpi) { @@ -301,7 +301,7 @@ static int ulpi_register(struct device *dev, struct ulpi *ulpi) return ret; } - root = debugfs_create_dir(dev_name(dev), ULPI_ROOT); + root = debugfs_create_dir(dev_name(dev), ulpi_root); debugfs_create_file("regs", 0444, root, ulpi, &ulpi_regs_fops); dev_dbg(&ulpi->dev, "registered ULPI PHY: vendor %04x, product %04x\n", @@ -349,8 +349,7 @@ EXPORT_SYMBOL_GPL(ulpi_register_interface); */ void ulpi_unregister_interface(struct ulpi *ulpi) { - debugfs_remove_recursive(debugfs_lookup(dev_name(&ulpi->dev), - ULPI_ROOT)); + debugfs_lookup_and_remove(dev_name(&ulpi->dev), ulpi_root); device_unregister(&ulpi->dev); } EXPORT_SYMBOL_GPL(ulpi_unregister_interface); @@ -360,12 +359,11 @@ EXPORT_SYMBOL_GPL(ulpi_unregister_interface); static int __init ulpi_init(void) { int ret; - struct dentry *root; - root = debugfs_create_dir(KBUILD_MODNAME, NULL); + ulpi_root = debugfs_create_dir(KBUILD_MODNAME, NULL); ret = bus_register(&ulpi_bus); if (ret) - debugfs_remove(root); + debugfs_remove(ulpi_root); return ret; } subsys_initcall(ulpi_init); @@ -373,7 +371,7 @@ subsys_initcall(ulpi_init); static void __exit ulpi_exit(void) { bus_unregister(&ulpi_bus); - debugfs_remove_recursive(ULPI_ROOT); + debugfs_remove(ulpi_root); } module_exit(ulpi_exit); From e529aeb771aef1402c899b6b405610ef444d5d88 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Feb 2023 16:32:25 +0100 Subject: [PATCH 146/201] USB: uhci: fix memory leak with using debugfs_lookup() [ Upstream commit 0a3f82c79c86278e7f144564b1cb6cc5c3657144 ] When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once. Cc: Alan Stern Link: https://lore.kernel.org/r/20230202153235.2412790-3-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/host/uhci-hcd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index c22b51af83fc..7cdc2fa7c28f 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -536,8 +536,8 @@ static void release_uhci(struct uhci_hcd *uhci) uhci->is_initialized = 0; spin_unlock_irq(&uhci->lock); - debugfs_remove(debugfs_lookup(uhci_to_hcd(uhci)->self.bus_name, - uhci_debugfs_root)); + debugfs_lookup_and_remove(uhci_to_hcd(uhci)->self.bus_name, + uhci_debugfs_root); for (i = 0; i < UHCI_NUM_SKELQH; i++) uhci_free_qh(uhci, uhci->skelqh[i]); @@ -700,7 +700,7 @@ err_alloc_frame_cpu: uhci->frame, uhci->frame_dma_handle); err_alloc_frame: - debugfs_remove(debugfs_lookup(hcd->self.bus_name, uhci_debugfs_root)); + debugfs_lookup_and_remove(hcd->self.bus_name, uhci_debugfs_root); return retval; } From 54166af8941d0cf46b65cfa2fbce76e38d82fadf Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Feb 2023 16:32:26 +0100 Subject: [PATCH 147/201] USB: sl811: fix memory leak with using debugfs_lookup() [ Upstream commit e1523c4dbc54e164638ff8729d511cf91e27be04 ] When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once. Cc: Vincent Mailhol Link: https://lore.kernel.org/r/20230202153235.2412790-4-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/host/sl811-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index d206bd95c7bb..b8b90eec9107 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1501,7 +1501,7 @@ static void create_debug_file(struct sl811 *sl811) static void remove_debug_file(struct sl811 *sl811) { - debugfs_remove(debugfs_lookup("sl811h", usb_debug_root)); + debugfs_lookup_and_remove("sl811h", usb_debug_root); } /*-------------------------------------------------------------------------*/ From 7d2d3bef6d700eb4261fb6761de2c95a9e3c0ac8 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Feb 2023 16:32:27 +0100 Subject: [PATCH 148/201] USB: fotg210: fix memory leak with using debugfs_lookup() [ Upstream commit 6b4040f452037a7e95472577891d57c6b18c89c5 ] When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once. Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20230202153235.2412790-5-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/host/fotg210-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c index 3d1dbcf4c073..c4c1fbc12b4c 100644 --- a/drivers/usb/host/fotg210-hcd.c +++ b/drivers/usb/host/fotg210-hcd.c @@ -862,7 +862,7 @@ static inline void remove_debug_files(struct fotg210_hcd *fotg210) { struct usb_bus *bus = &fotg210_to_hcd(fotg210)->self; - debugfs_remove(debugfs_lookup(bus->bus_name, fotg210_debug_root)); + debugfs_lookup_and_remove(bus->bus_name, fotg210_debug_root); } /* handshake - spin reading hc until handshake completes or fails From 542a99cd6eadfb543bf190431c3fb520f3da0bbc Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Feb 2023 16:32:28 +0100 Subject: [PATCH 149/201] USB: isp116x: fix memory leak with using debugfs_lookup() [ Upstream commit a95f62d5813facbec20ec087472eb313ee5fa8af ] When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once. Cc: Olav Kongas Link: https://lore.kernel.org/r/20230202153235.2412790-6-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/host/isp116x-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 4f564d71bb0b..49ae01487af4 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1205,7 +1205,7 @@ static void create_debug_file(struct isp116x *isp116x) static void remove_debug_file(struct isp116x *isp116x) { - debugfs_remove(debugfs_lookup(hcd_name, usb_debug_root)); + debugfs_lookup_and_remove(hcd_name, usb_debug_root); } #else From b0a8195a84a725ca7936c213b5e056d2a3ab2a94 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Feb 2023 16:32:29 +0100 Subject: [PATCH 150/201] USB: isp1362: fix memory leak with using debugfs_lookup() [ Upstream commit c26e682afc14caa87d44beed271eec8991e93c65 ] When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once. Cc: Vincent Mailhol Link: https://lore.kernel.org/r/20230202153235.2412790-7-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/host/isp1362-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index 0e14d1d07709..b0da143ef4be 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -2170,7 +2170,7 @@ static void create_debug_file(struct isp1362_hcd *isp1362_hcd) static void remove_debug_file(struct isp1362_hcd *isp1362_hcd) { - debugfs_remove(debugfs_lookup("isp1362", usb_debug_root)); + debugfs_lookup_and_remove("isp1362", usb_debug_root); } /*-------------------------------------------------------------------------*/ From be21a66e17ee0ab5f3513b6c86659e60cec5e981 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Feb 2023 16:32:30 +0100 Subject: [PATCH 151/201] USB: gadget: gr_udc: fix memory leak with using debugfs_lookup() [ Upstream commit 73f4451368663ad28daa67980c6dd11d83b303eb ] When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once. Cc: Jakob Koschel Link: https://lore.kernel.org/r/20230202153235.2412790-8-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/gadget/udc/gr_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c index 85cdc0af3bf9..09762559912d 100644 --- a/drivers/usb/gadget/udc/gr_udc.c +++ b/drivers/usb/gadget/udc/gr_udc.c @@ -215,7 +215,7 @@ static void gr_dfs_create(struct gr_udc *dev) static void gr_dfs_delete(struct gr_udc *dev) { - debugfs_remove(debugfs_lookup(dev_name(dev->dev), usb_debug_root)); + debugfs_lookup_and_remove(dev_name(dev->dev), usb_debug_root); } #else /* !CONFIG_USB_GADGET_DEBUG_FS */ From 31de0b70ae5661a407e9d578bbc41de2d83ac25d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Feb 2023 16:32:31 +0100 Subject: [PATCH 152/201] USB: gadget: bcm63xx_udc: fix memory leak with using debugfs_lookup() [ Upstream commit a91c99b1fe5c6f7e52fb932ad9e57ec7cfe913ec ] When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once. Cc: Kevin Cernekee Link: https://lore.kernel.org/r/20230202153235.2412790-9-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/gadget/udc/bcm63xx_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/bcm63xx_udc.c b/drivers/usb/gadget/udc/bcm63xx_udc.c index d04d72f5816e..8d5892891300 100644 --- a/drivers/usb/gadget/udc/bcm63xx_udc.c +++ b/drivers/usb/gadget/udc/bcm63xx_udc.c @@ -2258,7 +2258,7 @@ static void bcm63xx_udc_init_debugfs(struct bcm63xx_udc *udc) */ static void bcm63xx_udc_cleanup_debugfs(struct bcm63xx_udc *udc) { - debugfs_remove(debugfs_lookup(udc->gadget.name, usb_debug_root)); + debugfs_lookup_and_remove(udc->gadget.name, usb_debug_root); } /*********************************************************************** From 7a5fdd8660174a8056de57d1fdce3a7e9f77f60e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Feb 2023 16:32:32 +0100 Subject: [PATCH 153/201] USB: gadget: lpc32xx_udc: fix memory leak with using debugfs_lookup() [ Upstream commit e3965acaf3739fde9d74ad82979b46d37c6c208f ] When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once. Cc: Jakob Koschel Cc: Miaoqian Lin Acked-by: Vladimir Zapolskiy Link: https://lore.kernel.org/r/20230202153235.2412790-10-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/gadget/udc/lpc32xx_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index cea10cdb83ae..fe62db32dd0e 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -532,7 +532,7 @@ static void create_debug_file(struct lpc32xx_udc *udc) static void remove_debug_file(struct lpc32xx_udc *udc) { - debugfs_remove(debugfs_lookup(debug_filename, NULL)); + debugfs_lookup_and_remove(debug_filename, NULL); } #else From 78d9586d8e728be1e360d3d0da7170c791d1d55e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Feb 2023 16:32:33 +0100 Subject: [PATCH 154/201] USB: gadget: pxa25x_udc: fix memory leak with using debugfs_lookup() [ Upstream commit 7a038a681b7df78362d9fc7013e5395a694a9d3a ] When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once. Cc: Daniel Mack Cc: Haojian Zhuang Cc: Robert Jarzmik Link: https://lore.kernel.org/r/20230202153235.2412790-11-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/gadget/udc/pxa25x_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c index c593fc383481..9e01ddf2b417 100644 --- a/drivers/usb/gadget/udc/pxa25x_udc.c +++ b/drivers/usb/gadget/udc/pxa25x_udc.c @@ -1340,7 +1340,7 @@ DEFINE_SHOW_ATTRIBUTE(udc_debug); debugfs_create_file(dev->gadget.name, \ S_IRUGO, NULL, dev, &udc_debug_fops); \ } while (0) -#define remove_debug_files(dev) debugfs_remove(debugfs_lookup(dev->gadget.name, NULL)) +#define remove_debug_files(dev) debugfs_lookup_and_remove(dev->gadget.name, NULL) #else /* !CONFIG_USB_GADGET_DEBUG_FILES */ From b14d188d0d0b86e2180525aefd570dbb6ebd6aa9 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Feb 2023 16:32:34 +0100 Subject: [PATCH 155/201] USB: gadget: pxa27x_udc: fix memory leak with using debugfs_lookup() [ Upstream commit 7a6952fa0366d4408eb8695af1a0578c39ec718a ] When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once. Cc: Daniel Mack Cc: Haojian Zhuang Cc: Robert Jarzmik Link: https://lore.kernel.org/r/20230202153235.2412790-12-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/gadget/udc/pxa27x_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index ac980d6a4740..0ecdfd2ba9e9 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -215,7 +215,7 @@ static void pxa_init_debugfs(struct pxa_udc *udc) static void pxa_cleanup_debugfs(struct pxa_udc *udc) { - debugfs_remove(debugfs_lookup(udc->gadget.name, usb_debug_root)); + debugfs_lookup_and_remove(udc->gadget.name, usb_debug_root); } #else From cbf54771bc21e7320895730d2e73efa5eba25f63 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sat, 4 Feb 2023 10:36:52 -0800 Subject: [PATCH 156/201] usb: host: xhci: mvebu: Iterate over array indexes instead of using pointer math [ Upstream commit 0fbd2cda92cdb00f72080665554a586f88bca821 ] Walking the dram->cs array was seen as accesses beyond the first array item by the compiler. Instead, use the array index directly. This allows for run-time bounds checking under CONFIG_UBSAN_BOUNDS as well. Seen with GCC 13 with -fstrict-flex-arrays: In function 'xhci_mvebu_mbus_config', inlined from 'xhci_mvebu_mbus_init_quirk' at ../drivers/usb/host/xhci-mvebu.c:66:2: ../drivers/usb/host/xhci-mvebu.c:37:28: warning: array subscript 0 is outside array bounds of 'const struct mbus_dram_window[0]' [-Warray-bounds=] 37 | writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) | | ~~^~~~~~ Cc: Mathias Nyman Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20230204183651.never.663-kees@kernel.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/host/xhci-mvebu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-mvebu.c b/drivers/usb/host/xhci-mvebu.c index 60651a50770f..87f1597a0e5a 100644 --- a/drivers/usb/host/xhci-mvebu.c +++ b/drivers/usb/host/xhci-mvebu.c @@ -32,7 +32,7 @@ static void xhci_mvebu_mbus_config(void __iomem *base, /* Program each DRAM CS in a seperate window */ for (win = 0; win < dram->num_cs; win++) { - const struct mbus_dram_window *cs = dram->cs + win; + const struct mbus_dram_window *cs = &dram->cs[win]; writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) | (dram->mbus_dram_target_id << 4) | 1, From ff542083b105c9c72d83899d3f74eeec354f808e Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sat, 4 Feb 2023 10:35:46 -0800 Subject: [PATCH 157/201] USB: ene_usb6250: Allocate enough memory for full object [ Upstream commit ce33e64c1788912976b61314b56935abd4bc97ef ] The allocation of PageBuffer is 512 bytes in size, but the dereferencing of struct ms_bootblock_idi (also size 512) happens at a calculated offset within the allocation, which means the object could potentially extend beyond the end of the allocation. Avoid this case by just allocating enough space to catch any accesses beyond the end. Seen with GCC 13: ../drivers/usb/storage/ene_ub6250.c: In function 'ms_lib_process_bootblock': ../drivers/usb/storage/ene_ub6250.c:1050:44: warning: array subscript 'struct ms_bootblock_idi[0]' is partly outside array bounds of 'unsigned char[512]' [-Warray-bounds=] 1050 | if (le16_to_cpu(idi->wIDIgeneralConfiguration) != MS_IDI_GENERAL_CONF) | ^~ ../include/uapi/linux/byteorder/little_endian.h:37:51: note: in definition of macro '__le16_to_cpu' 37 | #define __le16_to_cpu(x) ((__force __u16)(__le16)(x)) | ^ ../drivers/usb/storage/ene_ub6250.c:1050:29: note: in expansion of macro 'le16_to_cpu' 1050 | if (le16_to_cpu(idi->wIDIgeneralConfiguration) != MS_IDI_GENERAL_CONF) | ^~~~~~~~~~~ In file included from ../drivers/usb/storage/ene_ub6250.c:5: In function 'kmalloc', inlined from 'ms_lib_process_bootblock' at ../drivers/usb/storage/ene_ub6250.c:942:15: ../include/linux/slab.h:580:24: note: at offset [256, 512] into object of size 512 allocated by 'kmalloc_trace' 580 | return kmalloc_trace( | ^~~~~~~~~~~~~~ 581 | kmalloc_caches[kmalloc_type(flags)][index], | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 582 | flags, size); | ~~~~~~~~~~~~ Cc: Alan Stern Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20230204183546.never.849-kees@kernel.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/storage/ene_ub6250.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c index 6012603f3630..97c66c0d91f4 100644 --- a/drivers/usb/storage/ene_ub6250.c +++ b/drivers/usb/storage/ene_ub6250.c @@ -939,7 +939,7 @@ static int ms_lib_process_bootblock(struct us_data *us, u16 PhyBlock, u8 *PageDa struct ms_lib_type_extdat ExtraData; struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - PageBuffer = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL); + PageBuffer = kzalloc(MS_BYTES_PER_PAGE * 2, GFP_KERNEL); if (PageBuffer == NULL) return (u32)-1; From 7a7de5957b8f86a50350e3e8a5b44a946eef0601 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 2 Feb 2023 11:41:37 +0000 Subject: [PATCH 158/201] usb: uvc: Enumerate valid values for color matching [ Upstream commit e16cab9c1596e251761d2bfb5e1467950d616963 ] The color matching descriptors defined in the UVC Specification contain 3 fields with discrete numeric values representing particular settings. Enumerate those values so that later code setting them can be more readable. Reviewed-by: Laurent Pinchart Signed-off-by: Daniel Scally Link: https://lore.kernel.org/r/20230202114142.300858-2-dan.scally@ideasonboard.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- include/uapi/linux/usb/video.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/include/uapi/linux/usb/video.h b/include/uapi/linux/usb/video.h index bfdae12cdacf..c58854fb7d94 100644 --- a/include/uapi/linux/usb/video.h +++ b/include/uapi/linux/usb/video.h @@ -179,6 +179,36 @@ #define UVC_CONTROL_CAP_AUTOUPDATE (1 << 3) #define UVC_CONTROL_CAP_ASYNCHRONOUS (1 << 4) +/* 3.9.2.6 Color Matching Descriptor Values */ +enum uvc_color_primaries_values { + UVC_COLOR_PRIMARIES_UNSPECIFIED, + UVC_COLOR_PRIMARIES_BT_709_SRGB, + UVC_COLOR_PRIMARIES_BT_470_2_M, + UVC_COLOR_PRIMARIES_BT_470_2_B_G, + UVC_COLOR_PRIMARIES_SMPTE_170M, + UVC_COLOR_PRIMARIES_SMPTE_240M, +}; + +enum uvc_transfer_characteristics_values { + UVC_TRANSFER_CHARACTERISTICS_UNSPECIFIED, + UVC_TRANSFER_CHARACTERISTICS_BT_709, + UVC_TRANSFER_CHARACTERISTICS_BT_470_2_M, + UVC_TRANSFER_CHARACTERISTICS_BT_470_2_B_G, + UVC_TRANSFER_CHARACTERISTICS_SMPTE_170M, + UVC_TRANSFER_CHARACTERISTICS_SMPTE_240M, + UVC_TRANSFER_CHARACTERISTICS_LINEAR, + UVC_TRANSFER_CHARACTERISTICS_SRGB, +}; + +enum uvc_matrix_coefficients { + UVC_MATRIX_COEFFICIENTS_UNSPECIFIED, + UVC_MATRIX_COEFFICIENTS_BT_709, + UVC_MATRIX_COEFFICIENTS_FCC, + UVC_MATRIX_COEFFICIENTS_BT_470_2_B_G, + UVC_MATRIX_COEFFICIENTS_SMPTE_170M, + UVC_MATRIX_COEFFICIENTS_SMPTE_240M, +}; + /* ------------------------------------------------------------------------ * UVC structures */ From 8dd58d3c1385bd4ee784b04d0d811dd81c95e49d Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Mon, 6 Feb 2023 16:17:52 +0000 Subject: [PATCH 159/201] usb: gadget: uvc: Make bSourceID read/write [ Upstream commit b3c839bd8a07d303bc59a900d55dd35c7826562c ] At the moment, the UVC function graph is hardcoded IT -> PU -> OT. To add XU support we need the ability to insert the XU descriptors into the chain. To facilitate that, make the output terminal's bSourceID attribute writeable so that we can configure its source. Signed-off-by: Daniel Scally Link: https://lore.kernel.org/r/20230206161802.892954-2-dan.scally@ideasonboard.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- .../ABI/testing/configfs-usb-gadget-uvc | 2 +- drivers/usb/gadget/function/uvc_configfs.c | 59 ++++++++++++++++++- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uvc b/Documentation/ABI/testing/configfs-usb-gadget-uvc index 611b23e6488d..feb3f2cc0c16 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-uvc +++ b/Documentation/ABI/testing/configfs-usb-gadget-uvc @@ -52,7 +52,7 @@ Date: Dec 2014 KernelVersion: 4.0 Description: Default output terminal descriptors - All attributes read only: + All attributes read only except bSourceID: ============== ============================================= iTerminal index of string descriptor diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 4303a3283ba0..832565730d22 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -483,11 +483,68 @@ UVC_ATTR_RO(uvcg_default_output_, cname, aname) UVCG_DEFAULT_OUTPUT_ATTR(b_terminal_id, bTerminalID, 8); UVCG_DEFAULT_OUTPUT_ATTR(w_terminal_type, wTerminalType, 16); UVCG_DEFAULT_OUTPUT_ATTR(b_assoc_terminal, bAssocTerminal, 8); -UVCG_DEFAULT_OUTPUT_ATTR(b_source_id, bSourceID, 8); UVCG_DEFAULT_OUTPUT_ATTR(i_terminal, iTerminal, 8); #undef UVCG_DEFAULT_OUTPUT_ATTR +static ssize_t uvcg_default_output_b_source_id_show(struct config_item *item, + char *page) +{ + struct config_group *group = to_config_group(item); + struct f_uvc_opts *opts; + struct config_item *opts_item; + struct mutex *su_mutex = &group->cg_subsys->su_mutex; + struct uvc_output_terminal_descriptor *cd; + int result; + + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ + + opts_item = group->cg_item.ci_parent->ci_parent-> + ci_parent->ci_parent; + opts = to_f_uvc_opts(opts_item); + cd = &opts->uvc_output_terminal; + + mutex_lock(&opts->lock); + result = sprintf(page, "%u\n", le8_to_cpu(cd->bSourceID)); + mutex_unlock(&opts->lock); + + mutex_unlock(su_mutex); + + return result; +} + +static ssize_t uvcg_default_output_b_source_id_store(struct config_item *item, + const char *page, size_t len) +{ + struct config_group *group = to_config_group(item); + struct f_uvc_opts *opts; + struct config_item *opts_item; + struct mutex *su_mutex = &group->cg_subsys->su_mutex; + struct uvc_output_terminal_descriptor *cd; + int result; + u8 num; + + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ + + opts_item = group->cg_item.ci_parent->ci_parent-> + ci_parent->ci_parent; + opts = to_f_uvc_opts(opts_item); + cd = &opts->uvc_output_terminal; + + result = kstrtou8(page, 0, &num); + if (result) + return result; + + mutex_lock(&opts->lock); + cd->bSourceID = num; + mutex_unlock(&opts->lock); + + mutex_unlock(su_mutex); + + return len; +} +UVC_ATTR(uvcg_default_output_, b_source_id, bSourceID); + static struct configfs_attribute *uvcg_default_output_attrs[] = { &uvcg_default_output_attr_b_terminal_id, &uvcg_default_output_attr_w_terminal_type, From a39f741e6021e52554cd2be044c6a51313e6215b Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 31 Jan 2023 11:24:03 +0200 Subject: [PATCH 160/201] PCI: Align extra resources for hotplug bridges properly [ Upstream commit 08f0a15ee8adb4846b08ca5d5c175fbf0f652bc9 ] After division the extra resource space per hotplug bridge may not be aligned according to the window alignment, so align it before passing it down for further distribution. Link: https://lore.kernel.org/r/20230131092405.29121-2-mika.westerberg@linux.intel.com Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Signed-off-by: Sasha Levin --- drivers/pci/setup-bus.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index b4096598dbcb..e440f264accb 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1891,6 +1891,7 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus, * resource space between hotplug bridges. */ for_each_pci_bridge(dev, bus) { + struct resource *res; struct pci_bus *b; b = dev->subordinate; @@ -1902,16 +1903,28 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus, * hotplug-capable downstream ports taking alignment into * account. */ - io.end = io.start + io_per_hp - 1; - mmio.end = mmio.start + mmio_per_hp - 1; - mmio_pref.end = mmio_pref.start + mmio_pref_per_hp - 1; + res = &dev->resource[PCI_BRIDGE_IO_WINDOW]; + align = pci_resource_alignment(dev, res); + io.end = align ? io.start + ALIGN_DOWN(io_per_hp, align) - 1 + : io.start + io_per_hp - 1; + + res = &dev->resource[PCI_BRIDGE_MEM_WINDOW]; + align = pci_resource_alignment(dev, res); + mmio.end = align ? mmio.start + ALIGN_DOWN(mmio_per_hp, align) - 1 + : mmio.start + mmio_per_hp - 1; + + res = &dev->resource[PCI_BRIDGE_PREF_MEM_WINDOW]; + align = pci_resource_alignment(dev, res); + mmio_pref.end = align ? mmio_pref.start + + ALIGN_DOWN(mmio_pref_per_hp, align) - 1 + : mmio_pref.start + mmio_pref_per_hp - 1; pci_bus_distribute_available_resources(b, add_list, io, mmio, mmio_pref); - io.start += io_per_hp; - mmio.start += mmio_per_hp; - mmio_pref.start += mmio_pref_per_hp; + io.start += io.end + 1; + mmio.start += mmio.end + 1; + mmio_pref.start += mmio_pref.end + 1; } } From bf1ab09d2c45e1ab1f7d401714857e12646231c3 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 31 Jan 2023 11:24:04 +0200 Subject: [PATCH 161/201] PCI: Take other bus devices into account when distributing resources [ Upstream commit 9db0b9b6a14249ef65a5f1e5e3b37762af96f425 ] A PCI bridge may reside on a bus with other devices as well. The resource distribution code does not take this into account and therefore it expands the bridge resource windows too much, not leaving space for the other devices (or functions of a multifunction device). This leads to an issue that Jonathan reported when running QEMU with the following topology (QEMU parameters): -device pcie-root-port,port=0,id=root_port13,chassis=0,slot=2 \ -device x3130-upstream,id=sw1,bus=root_port13,multifunction=on \ -device e1000,bus=root_port13,addr=0.1 \ -device xio3130-downstream,id=fun1,bus=sw1,chassis=0,slot=3 \ -device e1000,bus=fun1 The first e1000 NIC here is another function in the switch upstream port. This leads to following errors: pci 0000:00:04.0: bridge window [mem 0x10200000-0x103fffff] to [bus 02-04] pci 0000:02:00.0: bridge window [mem 0x10200000-0x103fffff] to [bus 03-04] pci 0000:02:00.1: BAR 0: failed to assign [mem size 0x00020000] e1000 0000:02:00.1: can't ioremap BAR 0: [??? 0x00000000 flags 0x0] Fix this by taking into account bridge windows, device BARs and SR-IOV PF BARs on the bus (PF BARs include space for VF BARS so only account PF BARs), including the ones belonging to bridges themselves if it has any. Link: https://lore.kernel.org/linux-pci/20221014124553.0000696f@huawei.com/ Link: https://lore.kernel.org/linux-pci/6053736d-1923-41e7-def9-7585ce1772d9@ixsystems.com/ Link: https://lore.kernel.org/r/20230131092405.29121-3-mika.westerberg@linux.intel.com Reported-by: Jonathan Cameron Reported-by: Alexander Motin Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Signed-off-by: Sasha Levin --- drivers/pci/setup-bus.c | 178 ++++++++++++++++++++++++---------------- 1 file changed, 107 insertions(+), 71 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index e440f264accb..b7b8dddb7772 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1765,12 +1765,67 @@ static void adjust_bridge_window(struct pci_dev *bridge, struct resource *res, add_size = size - new_size; pci_dbg(bridge, "bridge window %pR shrunken by %pa\n", res, &add_size); + } else { + return; } res->end = res->start + new_size - 1; remove_from_list(add_list, res); } +static void remove_dev_resource(struct resource *avail, struct pci_dev *dev, + struct resource *res) +{ + resource_size_t size, align, tmp; + + size = resource_size(res); + if (!size) + return; + + align = pci_resource_alignment(dev, res); + align = align ? ALIGN(avail->start, align) - avail->start : 0; + tmp = align + size; + avail->start = min(avail->start + tmp, avail->end + 1); +} + +static void remove_dev_resources(struct pci_dev *dev, struct resource *io, + struct resource *mmio, + struct resource *mmio_pref) +{ + int i; + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct resource *res = &dev->resource[i]; + + if (resource_type(res) == IORESOURCE_IO) { + remove_dev_resource(io, dev, res); + } else if (resource_type(res) == IORESOURCE_MEM) { + + /* + * Make sure prefetchable memory is reduced from + * the correct resource. Specifically we put 32-bit + * prefetchable memory in non-prefetchable window + * if there is an 64-bit pretchable window. + * + * See comments in __pci_bus_size_bridges() for + * more information. + */ + if ((res->flags & IORESOURCE_PREFETCH) && + ((res->flags & IORESOURCE_MEM_64) == + (mmio_pref->flags & IORESOURCE_MEM_64))) + remove_dev_resource(mmio_pref, dev, res); + else + remove_dev_resource(mmio, dev, res); + } + } +} + +/* + * io, mmio and mmio_pref contain the total amount of bridge window space + * available. This includes the minimal space needed to cover all the + * existing devices on the bus and the possible extra space that can be + * shared with the bridges. + */ static void pci_bus_distribute_available_resources(struct pci_bus *bus, struct list_head *add_list, struct resource io, @@ -1780,7 +1835,7 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus, unsigned int normal_bridges = 0, hotplug_bridges = 0; struct resource *io_res, *mmio_res, *mmio_pref_res; struct pci_dev *dev, *bridge = bus->self; - resource_size_t io_per_hp, mmio_per_hp, mmio_pref_per_hp, align; + resource_size_t io_per_b, mmio_per_b, mmio_pref_per_b, align; io_res = &bridge->resource[PCI_BRIDGE_IO_WINDOW]; mmio_res = &bridge->resource[PCI_BRIDGE_MEM_WINDOW]; @@ -1824,100 +1879,81 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus, normal_bridges++; } - /* - * There is only one bridge on the bus so it gets all available - * resources which it can then distribute to the possible hotplug - * bridges below. - */ - if (hotplug_bridges + normal_bridges == 1) { - dev = list_first_entry(&bus->devices, struct pci_dev, bus_list); - if (dev->subordinate) - pci_bus_distribute_available_resources(dev->subordinate, - add_list, io, mmio, mmio_pref); - return; - } - - if (hotplug_bridges == 0) + if (!(hotplug_bridges + normal_bridges)) return; /* - * Calculate the total amount of extra resource space we can - * pass to bridges below this one. This is basically the - * extra space reduced by the minimal required space for the - * non-hotplug bridges. + * Calculate the amount of space we can forward from "bus" to any + * downstream buses, i.e., the space left over after assigning the + * BARs and windows on "bus". */ - for_each_pci_bridge(dev, bus) { - resource_size_t used_size; - struct resource *res; - - if (dev->is_hotplug_bridge) - continue; - - /* - * Reduce the available resource space by what the - * bridge and devices below it occupy. - */ - res = &dev->resource[PCI_BRIDGE_IO_WINDOW]; - align = pci_resource_alignment(dev, res); - align = align ? ALIGN(io.start, align) - io.start : 0; - used_size = align + resource_size(res); - if (!res->parent) - io.start = min(io.start + used_size, io.end + 1); - - res = &dev->resource[PCI_BRIDGE_MEM_WINDOW]; - align = pci_resource_alignment(dev, res); - align = align ? ALIGN(mmio.start, align) - mmio.start : 0; - used_size = align + resource_size(res); - if (!res->parent) - mmio.start = min(mmio.start + used_size, mmio.end + 1); - - res = &dev->resource[PCI_BRIDGE_PREF_MEM_WINDOW]; - align = pci_resource_alignment(dev, res); - align = align ? ALIGN(mmio_pref.start, align) - - mmio_pref.start : 0; - used_size = align + resource_size(res); - if (!res->parent) - mmio_pref.start = min(mmio_pref.start + used_size, - mmio_pref.end + 1); + list_for_each_entry(dev, &bus->devices, bus_list) { + if (!dev->is_virtfn) + remove_dev_resources(dev, &io, &mmio, &mmio_pref); } - io_per_hp = div64_ul(resource_size(&io), hotplug_bridges); - mmio_per_hp = div64_ul(resource_size(&mmio), hotplug_bridges); - mmio_pref_per_hp = div64_ul(resource_size(&mmio_pref), - hotplug_bridges); - /* - * Go over devices on this bus and distribute the remaining - * resource space between hotplug bridges. + * If there is at least one hotplug bridge on this bus it gets all + * the extra resource space that was left after the reductions + * above. + * + * If there are no hotplug bridges the extra resource space is + * split between non-hotplug bridges. This is to allow possible + * hotplug bridges below them to get the extra space as well. */ + if (hotplug_bridges) { + io_per_b = div64_ul(resource_size(&io), hotplug_bridges); + mmio_per_b = div64_ul(resource_size(&mmio), hotplug_bridges); + mmio_pref_per_b = div64_ul(resource_size(&mmio_pref), + hotplug_bridges); + } else { + io_per_b = div64_ul(resource_size(&io), normal_bridges); + mmio_per_b = div64_ul(resource_size(&mmio), normal_bridges); + mmio_pref_per_b = div64_ul(resource_size(&mmio_pref), + normal_bridges); + } + for_each_pci_bridge(dev, bus) { struct resource *res; struct pci_bus *b; b = dev->subordinate; - if (!b || !dev->is_hotplug_bridge) + if (!b) + continue; + if (hotplug_bridges && !dev->is_hotplug_bridge) continue; - /* - * Distribute available extra resources equally between - * hotplug-capable downstream ports taking alignment into - * account. - */ res = &dev->resource[PCI_BRIDGE_IO_WINDOW]; + + /* + * Make sure the split resource space is properly aligned + * for bridge windows (align it down to avoid going above + * what is available). + */ align = pci_resource_alignment(dev, res); - io.end = align ? io.start + ALIGN_DOWN(io_per_hp, align) - 1 - : io.start + io_per_hp - 1; + io.end = align ? io.start + ALIGN_DOWN(io_per_b, align) - 1 + : io.start + io_per_b - 1; + + /* + * The x_per_b holds the extra resource space that can be + * added for each bridge but there is the minimal already + * reserved as well so adjust x.start down accordingly to + * cover the whole space. + */ + io.start -= resource_size(res); res = &dev->resource[PCI_BRIDGE_MEM_WINDOW]; align = pci_resource_alignment(dev, res); - mmio.end = align ? mmio.start + ALIGN_DOWN(mmio_per_hp, align) - 1 - : mmio.start + mmio_per_hp - 1; + mmio.end = align ? mmio.start + ALIGN_DOWN(mmio_per_b, align) - 1 + : mmio.start + mmio_per_b - 1; + mmio.start -= resource_size(res); res = &dev->resource[PCI_BRIDGE_PREF_MEM_WINDOW]; align = pci_resource_alignment(dev, res); mmio_pref.end = align ? mmio_pref.start + - ALIGN_DOWN(mmio_pref_per_hp, align) - 1 - : mmio_pref.start + mmio_pref_per_hp - 1; + ALIGN_DOWN(mmio_pref_per_b, align) - 1 + : mmio_pref.start + mmio_pref_per_b - 1; + mmio_pref.start -= resource_size(res); pci_bus_distribute_available_resources(b, add_list, io, mmio, mmio_pref); From d1589b73519eb7454cbc2b7b29f65f7bba64270b Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 31 Jan 2023 11:24:05 +0200 Subject: [PATCH 162/201] PCI: Distribute available resources for root buses, too [ Upstream commit 7180c1d08639f28e63110ad35815f7a1785b8a19 ] Previously we distributed spare resources only upon hot-add, so if the initial root bus scan found devices that had not been fully configured by the BIOS, we allocated only enough resources to cover what was then present. If some of those devices were hotplug bridges, we did not leave any additional resource space for future expansion. Distribute the available resources for root buses, too, to make this work the same way as the normal hotplug case. A previous commit to do this was reverted due to a regression reported by Jonathan Cameron: e96e27fc6f79 ("PCI: Distribute available resources for root buses, too") 5632e2beaf9d ("Revert "PCI: Distribute available resources for root buses, too"") This commit changes pci_bridge_resources_not_assigned() to work with bridges that do not have all the resource windows programmed by the boot firmware (previously we expected all I/O, memory and prefetchable memory were programmed). Link: https://bugzilla.kernel.org/show_bug.cgi?id=216000 Link: https://lore.kernel.org/r/20220905080232.36087-5-mika.westerberg@linux.intel.com Link: https://lore.kernel.org/r/20230131092405.29121-4-mika.westerberg@linux.intel.com Reported-by: Chris Chiu Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Signed-off-by: Sasha Levin --- drivers/pci/setup-bus.c | 57 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index b7b8dddb7772..c690572b10ce 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1770,7 +1770,10 @@ static void adjust_bridge_window(struct pci_dev *bridge, struct resource *res, } res->end = res->start + new_size - 1; - remove_from_list(add_list, res); + + /* If the resource is part of the add_list, remove it now */ + if (add_list) + remove_from_list(add_list, res); } static void remove_dev_resource(struct resource *avail, struct pci_dev *dev, @@ -1972,6 +1975,8 @@ static void pci_bridge_distribute_available_resources(struct pci_dev *bridge, if (!bridge->is_hotplug_bridge) return; + pci_dbg(bridge, "distributing available resources\n"); + /* Take the initial extra resources from the hotplug port */ available_io = bridge->resource[PCI_BRIDGE_IO_WINDOW]; available_mmio = bridge->resource[PCI_BRIDGE_MEM_WINDOW]; @@ -1983,6 +1988,54 @@ static void pci_bridge_distribute_available_resources(struct pci_dev *bridge, available_mmio_pref); } +static bool pci_bridge_resources_not_assigned(struct pci_dev *dev) +{ + const struct resource *r; + + /* + * If the child device's resources are not yet assigned it means we + * are configuring them (not the boot firmware), so we should be + * able to extend the upstream bridge resources in the same way we + * do with the normal hotplug case. + */ + r = &dev->resource[PCI_BRIDGE_IO_WINDOW]; + if (r->flags && !(r->flags & IORESOURCE_STARTALIGN)) + return false; + r = &dev->resource[PCI_BRIDGE_MEM_WINDOW]; + if (r->flags && !(r->flags & IORESOURCE_STARTALIGN)) + return false; + r = &dev->resource[PCI_BRIDGE_PREF_MEM_WINDOW]; + if (r->flags && !(r->flags & IORESOURCE_STARTALIGN)) + return false; + + return true; +} + +static void +pci_root_bus_distribute_available_resources(struct pci_bus *bus, + struct list_head *add_list) +{ + struct pci_dev *dev, *bridge = bus->self; + + for_each_pci_bridge(dev, bus) { + struct pci_bus *b; + + b = dev->subordinate; + if (!b) + continue; + + /* + * Need to check "bridge" here too because it is NULL + * in case of root bus. + */ + if (bridge && pci_bridge_resources_not_assigned(dev)) + pci_bridge_distribute_available_resources(bridge, + add_list); + else + pci_root_bus_distribute_available_resources(b, add_list); + } +} + /* * First try will not touch PCI bridge res. * Second and later try will clear small leaf bridge res. @@ -2022,6 +2075,8 @@ again: */ __pci_bus_size_bridges(bus, add_list); + pci_root_bus_distribute_available_resources(bus, add_list); + /* Depth last, allocate resources and update the hardware. */ __pci_bus_assign_resources(bus, add_list, &fail_head); if (add_list) From 4459d1e7bd0421b3b6fcd745773d8823f71615ef Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Feb 2023 15:12:21 +0100 Subject: [PATCH 163/201] tty: pcn_uart: fix memory leak with using debugfs_lookup() [ Upstream commit 04a189c720aa2b6091442113ce9b9bc93552dff8 ] When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once. Cc: Jiri Slaby Link: https://lore.kernel.org/r/20230202141221.2293012-1-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/tty/serial/pch_uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 83f35b7b0897..abff1c6470f6 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1779,7 +1779,7 @@ static void pch_uart_exit_port(struct eg20t_port *priv) char name[32]; snprintf(name, sizeof(name), "uart%d_regs", priv->port.line); - debugfs_remove(debugfs_lookup(name, NULL)); + debugfs_lookup_and_remove(name, NULL); uart_remove_one_port(&pch_uart_driver, &priv->port); free_page((unsigned long)priv->rxbuf.buf); } From d1c545e44c1ec08bef0c0c14e632eec516431e9c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Feb 2023 15:11:00 +0100 Subject: [PATCH 164/201] misc: vmw_balloon: fix memory leak with using debugfs_lookup() [ Upstream commit 209cdbd07cfaa4b7385bad4eeb47e5ec1887d33d ] When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once. Cc: Nadav Amit Cc: VMware PV-Drivers Reviewers Cc: Arnd Bergmann Link: https://lore.kernel.org/r/20230202141100.2291188-1-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/misc/vmw_balloon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 61a2be712bf7..9ce9b9e0e9b6 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -1709,7 +1709,7 @@ static void __init vmballoon_debugfs_init(struct vmballoon *b) static void __exit vmballoon_debugfs_exit(struct vmballoon *b) { static_key_disable(&balloon_stat_enabled.key); - debugfs_remove(debugfs_lookup("vmmemctl", NULL)); + debugfs_lookup_and_remove("vmmemctl", NULL); kfree(b->stats); b->stats = NULL; } From 79ac2b01e033181e21cc84216ace1f4160eb8950 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Feb 2023 15:16:20 +0100 Subject: [PATCH 165/201] drivers: base: component: fix memory leak with using debugfs_lookup() [ Upstream commit 8deb87b1e810dd558371e88ffd44339fbef27870 ] When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once. Cc: "Rafael J. Wysocki" Link: https://lore.kernel.org/r/20230202141621.2296458-1-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/base/component.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/component.c b/drivers/base/component.c index 5eadeac6c532..7dbf14a1d915 100644 --- a/drivers/base/component.c +++ b/drivers/base/component.c @@ -125,7 +125,7 @@ static void component_debugfs_add(struct aggregate_device *m) static void component_debugfs_del(struct aggregate_device *m) { - debugfs_remove(debugfs_lookup(dev_name(m->parent), component_debugfs_dir)); + debugfs_lookup_and_remove(dev_name(m->parent), component_debugfs_dir); } #else From 5a7a9efdb193d3c8a35821548a8e99612c358828 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Feb 2023 15:16:21 +0100 Subject: [PATCH 166/201] drivers: base: dd: fix memory leak with using debugfs_lookup() [ Upstream commit 36c893d3a759ae7c91ee7d4871ebfc7504f08c40 ] When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once. Cc: "Rafael J. Wysocki" Link: https://lore.kernel.org/r/20230202141621.2296458-2-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/base/dd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 9ae2b5c4fc49..c463173f1fb1 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -372,7 +372,7 @@ late_initcall(deferred_probe_initcall); static void __exit deferred_probe_exit(void) { - debugfs_remove_recursive(debugfs_lookup("devices_deferred", NULL)); + debugfs_lookup_and_remove("devices_deferred", NULL); } __exitcall(deferred_probe_exit); From 29d53c4c5a6f6d2b93aaac95b65cb4c907faf2ff Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Feb 2023 16:16:33 +0100 Subject: [PATCH 167/201] kernel/fail_function: fix memory leak with using debugfs_lookup() [ Upstream commit 2bb3669f576559db273efe49e0e69f82450efbca ] When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once. Cc: Andrew Morton Reviewed-by: Yang Yingliang Link: https://lore.kernel.org/r/20230202151633.2310897-1-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- kernel/fail_function.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/kernel/fail_function.c b/kernel/fail_function.c index a7ccd2930c5f..d971a0189319 100644 --- a/kernel/fail_function.c +++ b/kernel/fail_function.c @@ -163,10 +163,7 @@ static void fei_debugfs_add_attr(struct fei_attr *attr) static void fei_debugfs_remove_attr(struct fei_attr *attr) { - struct dentry *dir; - - dir = debugfs_lookup(attr->kp.symbol_name, fei_debugfs_dir); - debugfs_remove_recursive(dir); + debugfs_lookup_and_remove(attr->kp.symbol_name, fei_debugfs_dir); } static int fei_kprobe_handler(struct kprobe *kp, struct pt_regs *regs) From 2d07ad44e7414d3326af92adf3b2d31707321f6e Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Sat, 11 Feb 2023 10:33:21 +0800 Subject: [PATCH 168/201] PCI: loongson: Add more devices that need MRRS quirk [ Upstream commit c768f8c5f40fcdc6f058cc2f02592163d6c6716c ] Loongson-2K SOC and LS7A2000 chipset add new PCI IDs that need MRRS quirk. Add them. Link: https://lore.kernel.org/r/20230211023321.3530080-1-chenhuacai@loongson.cn Signed-off-by: Huacai Chen Signed-off-by: Bjorn Helgaas Signed-off-by: Sasha Levin --- drivers/pci/controller/pci-loongson.c | 33 +++++++++++++++++++-------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/drivers/pci/controller/pci-loongson.c b/drivers/pci/controller/pci-loongson.c index 759ec211c17b..fe0f732f6e43 100644 --- a/drivers/pci/controller/pci-loongson.c +++ b/drivers/pci/controller/pci-loongson.c @@ -15,9 +15,14 @@ #include "../pci.h" /* Device IDs */ -#define DEV_PCIE_PORT_0 0x7a09 -#define DEV_PCIE_PORT_1 0x7a19 -#define DEV_PCIE_PORT_2 0x7a29 +#define DEV_LS2K_PCIE_PORT0 0x1a05 +#define DEV_LS7A_PCIE_PORT0 0x7a09 +#define DEV_LS7A_PCIE_PORT1 0x7a19 +#define DEV_LS7A_PCIE_PORT2 0x7a29 +#define DEV_LS7A_PCIE_PORT3 0x7a39 +#define DEV_LS7A_PCIE_PORT4 0x7a49 +#define DEV_LS7A_PCIE_PORT5 0x7a59 +#define DEV_LS7A_PCIE_PORT6 0x7a69 #define DEV_LS2K_APB 0x7a02 #define DEV_LS7A_GMAC 0x7a03 @@ -53,11 +58,11 @@ static void bridge_class_quirk(struct pci_dev *dev) dev->class = PCI_CLASS_BRIDGE_PCI_NORMAL; } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, - DEV_PCIE_PORT_0, bridge_class_quirk); + DEV_LS7A_PCIE_PORT0, bridge_class_quirk); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, - DEV_PCIE_PORT_1, bridge_class_quirk); + DEV_LS7A_PCIE_PORT1, bridge_class_quirk); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, - DEV_PCIE_PORT_2, bridge_class_quirk); + DEV_LS7A_PCIE_PORT2, bridge_class_quirk); static void system_bus_quirk(struct pci_dev *pdev) { @@ -87,11 +92,21 @@ static void loongson_mrrs_quirk(struct pci_dev *pdev) bridge->no_inc_mrrs = 1; } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, - DEV_PCIE_PORT_0, loongson_mrrs_quirk); + DEV_LS2K_PCIE_PORT0, loongson_mrrs_quirk); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, - DEV_PCIE_PORT_1, loongson_mrrs_quirk); + DEV_LS7A_PCIE_PORT0, loongson_mrrs_quirk); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, - DEV_PCIE_PORT_2, loongson_mrrs_quirk); + DEV_LS7A_PCIE_PORT1, loongson_mrrs_quirk); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, + DEV_LS7A_PCIE_PORT2, loongson_mrrs_quirk); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, + DEV_LS7A_PCIE_PORT3, loongson_mrrs_quirk); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, + DEV_LS7A_PCIE_PORT4, loongson_mrrs_quirk); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, + DEV_LS7A_PCIE_PORT5, loongson_mrrs_quirk); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, + DEV_LS7A_PCIE_PORT6, loongson_mrrs_quirk); static void loongson_pci_pin_quirk(struct pci_dev *pdev) { From 455ed25b59452e55756fb7d947f02fbc270ac70e Mon Sep 17 00:00:00 2001 From: Mengyuan Lou Date: Tue, 7 Feb 2023 18:24:19 +0800 Subject: [PATCH 169/201] PCI: Add ACS quirk for Wangxun NICs [ Upstream commit a2b9b123ccac913e9f9b80337d687a2fe786a634 ] Wangxun has verified there is no peer-to-peer between functions for the below selection of SFxxx, RP1000 and RP2000 NICS. They may be multi-function devices, but the hardware does not advertise ACS capability. Add an ACS quirk for these devices so the functions can be in independent IOMMU groups. Link: https://lore.kernel.org/r/20230207102419.44326-1-mengyuanlou@net-swift.com Signed-off-by: Mengyuan Lou Signed-off-by: Bjorn Helgaas Signed-off-by: Sasha Levin --- drivers/pci/quirks.c | 22 ++++++++++++++++++++++ include/linux/pci_ids.h | 2 ++ 2 files changed, 24 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 20ac67d59034..494fa46f5767 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4835,6 +4835,26 @@ static int pci_quirk_brcm_acs(struct pci_dev *dev, u16 acs_flags) PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); } +/* + * Wangxun 10G/1G NICs have no ACS capability, and on multi-function + * devices, peer-to-peer transactions are not be used between the functions. + * So add an ACS quirk for below devices to isolate functions. + * SFxxx 1G NICs(em). + * RP1000/RP2000 10G NICs(sp). + */ +static int pci_quirk_wangxun_nic_acs(struct pci_dev *dev, u16 acs_flags) +{ + switch (dev->device) { + case 0x0100 ... 0x010F: + case 0x1001: + case 0x2001: + return pci_acs_ctrl_enabled(acs_flags, + PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); + } + + return false; +} + static const struct pci_dev_acs_enabled { u16 vendor; u16 device; @@ -4980,6 +5000,8 @@ static const struct pci_dev_acs_enabled { { PCI_VENDOR_ID_NXP, 0x8d9b, pci_quirk_nxp_rp_acs }, /* Zhaoxin Root/Downstream Ports */ { PCI_VENDOR_ID_ZHAOXIN, PCI_ANY_ID, pci_quirk_zhaoxin_pcie_ports_acs }, + /* Wangxun nics */ + { PCI_VENDOR_ID_WANGXUN, PCI_ANY_ID, pci_quirk_wangxun_nic_acs }, { 0 } }; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index b362d90eb9b0..bc8f484cdcf3 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -3012,6 +3012,8 @@ #define PCI_DEVICE_ID_INTEL_VMD_9A0B 0x9a0b #define PCI_DEVICE_ID_INTEL_S21152BB 0xb152 +#define PCI_VENDOR_ID_WANGXUN 0x8088 + #define PCI_VENDOR_ID_SCALEMP 0x8686 #define PCI_DEVICE_ID_SCALEMP_VSMP_CTL 0x1010 From 52ec1cae5277055cfc8d6ac062947f965bdede3e Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 13 Feb 2023 20:19:22 +0530 Subject: [PATCH 170/201] PCI: pciehp: Add Qualcomm quirk for Command Completed erratum [ Upstream commit 82b34b0800af8c9fc9988c290cdc813e0ca0df31 ] The Qualcomm PCI bridge device (Device ID 0x010e) found in chipsets such as SC8280XP used in Lenovo Thinkpad X13s, does not set the Command Completed bit unless writes to the Slot Command register change "Control" bits. This results in timeouts like below during boot and resume from suspend: pcieport 0002:00:00.0: pciehp: Timeout on hotplug command 0x03c0 (issued 2020 msec ago) ... pcieport 0002:00:00.0: pciehp: Timeout on hotplug command 0x13f1 (issued 107724 msec ago) Add the device to the Command Completed quirk to mark commands "completed" immediately unless they change the "Control" bits. Link: https://lore.kernel.org/r/20230213144922.89982-1-manivannan.sadhasivam@linaro.org Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Signed-off-by: Sasha Levin --- drivers/pci/hotplug/pciehp_hpc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 040ae076ec0e..112c8f401ac4 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -1086,6 +1086,8 @@ static void quirk_cmd_compl(struct pci_dev *pdev) } DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl); +DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_QCOM, 0x010e, + PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl); DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_QCOM, 0x0110, PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl); DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_QCOM, 0x0400, From a577aac0dac6148fa7e6be606fe03ffb4b9d1485 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Mon, 13 Feb 2023 11:57:09 +0800 Subject: [PATCH 171/201] phy: rockchip-typec: Fix unsigned comparison with less than zero [ Upstream commit f765c59c5a72546a2d74a92ae5d0eb0329d8e247 ] The dp and ufp are defined as bool type, the return value type of function extcon_get_state should be int, so the type of dp and ufp are modified to int. ./drivers/phy/rockchip/phy-rockchip-typec.c:827:12-14: WARNING: Unsigned expression compared with zero: dp > 0. Reported-by: Abaci Robot Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=3962 Signed-off-by: Jiapeng Chong Link: https://lore.kernel.org/r/20230213035709.99027-1-jiapeng.chong@linux.alibaba.com Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/phy/rockchip/phy-rockchip-typec.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 6aea512e5d4e..39db8acde61a 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -808,9 +808,8 @@ static int tcphy_get_mode(struct rockchip_typec_phy *tcphy) struct extcon_dev *edev = tcphy->extcon; union extcon_property_value property; unsigned int id; - bool ufp, dp; u8 mode; - int ret; + int ret, ufp, dp; if (!edev) return MODE_DFP_USB; From 4e11ac106f69e4776dc98363a064c105bd1a8a50 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 8 Feb 2023 15:25:53 -0800 Subject: [PATCH 172/201] RDMA/cma: Distinguish between sockaddr_in and sockaddr_in6 by size [ Upstream commit 876e480da2f74715fc70e37723e77ca16a631e35 ] Clang can do some aggressive inlining, which provides it with greater visibility into the sizes of various objects that are passed into helpers. Specifically, compare_netdev_and_ip() can see through the type given to the "sa" argument, which means it can generate code for "struct sockaddr_in" that would have been passed to ipv6_addr_cmp() (that expects to operate on the larger "struct sockaddr_in6"), which would result in a compile-time buffer overflow condition detected by memcmp(). Logically, this state isn't reachable due to the sa_family assignment two callers above and the check in compare_netdev_and_ip(). Instead, provide a compile-time check on sizes so the size-mismatched code will be elided when inlining. Avoids the following warning from Clang: ../include/linux/fortify-string.h:652:4: error: call to '__read_overflow' declared with 'error' attribute: detected read beyond size of object (1st parameter) __read_overflow(); ^ note: In function 'cma_netevent_callback' note: which inlined function 'node_from_ndev_ip' 1 error generated. When the underlying object size is not known (e.g. with GCC and older Clang), the result of __builtin_object_size() is SIZE_MAX, which will also compile away, leaving the code as it was originally. Link: https://lore.kernel.org/r/20230208232549.never.139-kees@kernel.org Link: https://github.com/ClangBuiltLinux/linux/issues/1687 Signed-off-by: Kees Cook Tested-by: Nathan Chancellor # build Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- drivers/infiniband/core/cma.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 26d1772179b8..8730674ceb2e 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -479,13 +479,20 @@ static int compare_netdev_and_ip(int ifindex_a, struct sockaddr *sa, if (sa->sa_family != sb->sa_family) return sa->sa_family - sb->sa_family; - if (sa->sa_family == AF_INET) - return memcmp((char *)&((struct sockaddr_in *)sa)->sin_addr, - (char *)&((struct sockaddr_in *)sb)->sin_addr, + if (sa->sa_family == AF_INET && + __builtin_object_size(sa, 0) >= sizeof(struct sockaddr_in)) { + return memcmp(&((struct sockaddr_in *)sa)->sin_addr, + &((struct sockaddr_in *)sb)->sin_addr, sizeof(((struct sockaddr_in *)sa)->sin_addr)); + } - return ipv6_addr_cmp(&((struct sockaddr_in6 *)sa)->sin6_addr, - &((struct sockaddr_in6 *)sb)->sin6_addr); + if (sa->sa_family == AF_INET6 && + __builtin_object_size(sa, 0) >= sizeof(struct sockaddr_in6)) { + return ipv6_addr_cmp(&((struct sockaddr_in6 *)sa)->sin6_addr, + &((struct sockaddr_in6 *)sb)->sin6_addr); + } + + return -1; } static int cma_add_id_to_tree(struct rdma_id_private *node_id_priv) From 425cd1b471245fecd9630f65ee93e21ff6b152f0 Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Wed, 15 Feb 2023 05:26:40 +0000 Subject: [PATCH 173/201] iommu: Attach device group to old domain in error path [ Upstream commit 2cc73c5712f97de98c38c2fafc1f288354a9f3c3 ] iommu_attach_group() attaches all devices in a group to domain and then sets group domain (group->domain). Current code (__iommu_attach_group()) does not handle error path. This creates problem as devices to domain attachment is in inconsistent state. Flow: - During boot iommu attach devices to default domain - Later some device driver (like amd/iommu_v2 or vfio) tries to attach device to new domain. - In iommu_attach_group() path we detach device from current domain. Then it tries to attach devices to new domain. - If it fails to attach device to new domain then device to domain link is broken. - iommu_attach_group() returns error. - At this stage iommu_attach_group() caller thinks, attaching device to new domain failed and devices are still attached to old domain. - But in reality device to old domain link is broken. It will result in all sort of failures (like IO page fault) later. To recover from this situation, we need to attach all devices back to the old domain. Also log warning if it fails attach device back to old domain. Suggested-by: Lu Baolu Reported-by: Matt Fagnani Signed-off-by: Vasant Hegde Reviewed-by: Jason Gunthorpe Tested-by: Matt Fagnani Link: https://lore.kernel.org/r/20230215052642.6016-1-vasant.hegde@amd.com Link: https://bugzilla.kernel.org/show_bug.cgi?id=216865 Link: https://lore.kernel.org/lkml/15d0f9ff-2a56-b3e9-5b45-e6b23300ae3b@leemhuis.info/ Signed-off-by: Joerg Roedel Signed-off-by: Sasha Levin --- drivers/iommu/iommu.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index fd8c8aeb3c50..bfb2f163c691 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -2089,8 +2089,22 @@ static int __iommu_attach_group(struct iommu_domain *domain, ret = __iommu_group_for_each_dev(group, domain, iommu_group_do_attach_device); - if (ret == 0) + if (ret == 0) { group->domain = domain; + } else { + /* + * To recover from the case when certain device within the + * group fails to attach to the new domain, we need force + * attaching all devices back to the old domain. The old + * domain is compatible for all devices in the group, + * hence the iommu driver should always return success. + */ + struct iommu_domain *old_domain = group->domain; + + group->domain = NULL; + WARN(__iommu_group_set_domain(group, old_domain), + "iommu driver failed to attach a compatible domain"); + } return ret; } From 51eb90be9fd8cfb4d037a06bc55eb28b1aa0f406 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 2 Dec 2022 16:18:11 +0000 Subject: [PATCH 174/201] soundwire: cadence: Remove wasted space in response_buf [ Upstream commit 827c32d0df4bbe0d1c47d79f6a5eabfe9ac75216 ] The response_buf was declared much larger (128 entries) than the number of responses that could ever be written into it. The Cadence IP is configurable up to a maximum of 32 entries, and the datasheet says that RX_FIFO_AVAIL can be 2 larger than this. So allow up to 34 responses. Also add checking in cdns_read_response() to prevent overflowing reponse_buf if RX_FIFO_AVAIL contains an unexpectedly large number. Signed-off-by: Richard Fitzgerald Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20221202161812.4186897-3-rf@opensource.cirrus.com Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/soundwire/cadence_master.c | 7 +++++++ drivers/soundwire/cadence_master.h | 13 ++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index b65cdf2a7593..6cd9db19758c 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -774,8 +774,15 @@ static void cdns_read_response(struct sdw_cdns *cdns) u32 num_resp, cmd_base; int i; + /* RX_FIFO_AVAIL can be 2 entries more than the FIFO size */ + BUILD_BUG_ON(ARRAY_SIZE(cdns->response_buf) < CDNS_MCP_CMD_LEN + 2); + num_resp = cdns_readl(cdns, CDNS_MCP_FIFOSTAT); num_resp &= CDNS_MCP_RX_FIFO_AVAIL; + if (num_resp > ARRAY_SIZE(cdns->response_buf)) { + dev_warn(cdns->dev, "RX AVAIL %d too long\n", num_resp); + num_resp = ARRAY_SIZE(cdns->response_buf); + } cmd_base = CDNS_MCP_CMD_BASE; diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index ca9e805bab88..51e6ecc027cb 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -8,6 +8,12 @@ #define SDW_CADENCE_GSYNC_KHZ 4 /* 4 kHz */ #define SDW_CADENCE_GSYNC_HZ (SDW_CADENCE_GSYNC_KHZ * 1000) +/* + * The Cadence IP supports up to 32 entries in the FIFO, though implementations + * can configure the IP to have a smaller FIFO. + */ +#define CDNS_MCP_IP_MAX_CMD_LEN 32 + /** * struct sdw_cdns_pdi: PDI (Physical Data Interface) instance * @@ -114,7 +120,12 @@ struct sdw_cdns { struct sdw_bus bus; unsigned int instance; - u32 response_buf[0x80]; + /* + * The datasheet says the RX FIFO AVAIL can be 2 entries more + * than the FIFO capacity, so allow for this. + */ + u32 response_buf[CDNS_MCP_IP_MAX_CMD_LEN + 2]; + struct completion tx_complete; struct sdw_defer *defer; From f5a21755ee55cc37465bfb2bb9ada61719010cf6 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 2 Dec 2022 16:18:12 +0000 Subject: [PATCH 175/201] soundwire: cadence: Drain the RX FIFO after an IO timeout [ Upstream commit 0603a47bd3a8f439d7844b841eee1819353063e0 ] If wait_for_completion_timeout() times-out in _cdns_xfer_msg() it is possible that something could have been written to the RX FIFO. In this case, we should drain the RX FIFO so that anything in it doesn't carry over and mess up the next transfer. Obviously, if we got to this state something went wrong, and we don't really know the state of everything. The cleanup in this situation cannot be bullet-proof but we should attempt to avoid breaking future transaction, if only to reduce the amount of error noise when debugging the failure from a kernel log. Note that this patch only implements the draining for blocking (non-deferred) transfers. The deferred API doesn't have any proper handling of error conditions and would need some re-design before implementing cleanup. That is a task for a separate patch... Signed-off-by: Richard Fitzgerald Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20221202161812.4186897-4-rf@opensource.cirrus.com Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/soundwire/cadence_master.c | 50 ++++++++++++++++-------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 6cd9db19758c..e7da7d7b213f 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -555,6 +555,29 @@ cdns_fill_msg_resp(struct sdw_cdns *cdns, return SDW_CMD_OK; } +static void cdns_read_response(struct sdw_cdns *cdns) +{ + u32 num_resp, cmd_base; + int i; + + /* RX_FIFO_AVAIL can be 2 entries more than the FIFO size */ + BUILD_BUG_ON(ARRAY_SIZE(cdns->response_buf) < CDNS_MCP_CMD_LEN + 2); + + num_resp = cdns_readl(cdns, CDNS_MCP_FIFOSTAT); + num_resp &= CDNS_MCP_RX_FIFO_AVAIL; + if (num_resp > ARRAY_SIZE(cdns->response_buf)) { + dev_warn(cdns->dev, "RX AVAIL %d too long\n", num_resp); + num_resp = ARRAY_SIZE(cdns->response_buf); + } + + cmd_base = CDNS_MCP_CMD_BASE; + + for (i = 0; i < num_resp; i++) { + cdns->response_buf[i] = cdns_readl(cdns, cmd_base); + cmd_base += CDNS_MCP_CMD_WORD_LEN; + } +} + static enum sdw_command_response _cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd, int offset, int count, bool defer) @@ -596,6 +619,10 @@ _cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd, dev_err(cdns->dev, "IO transfer timed out, cmd %d device %d addr %x len %d\n", cmd, msg->dev_num, msg->addr, msg->len); msg->len = 0; + + /* Drain anything in the RX_FIFO */ + cdns_read_response(cdns); + return SDW_CMD_TIMEOUT; } @@ -769,29 +796,6 @@ EXPORT_SYMBOL(cdns_read_ping_status); * IRQ handling */ -static void cdns_read_response(struct sdw_cdns *cdns) -{ - u32 num_resp, cmd_base; - int i; - - /* RX_FIFO_AVAIL can be 2 entries more than the FIFO size */ - BUILD_BUG_ON(ARRAY_SIZE(cdns->response_buf) < CDNS_MCP_CMD_LEN + 2); - - num_resp = cdns_readl(cdns, CDNS_MCP_FIFOSTAT); - num_resp &= CDNS_MCP_RX_FIFO_AVAIL; - if (num_resp > ARRAY_SIZE(cdns->response_buf)) { - dev_warn(cdns->dev, "RX AVAIL %d too long\n", num_resp); - num_resp = ARRAY_SIZE(cdns->response_buf); - } - - cmd_base = CDNS_MCP_CMD_BASE; - - for (i = 0; i < num_resp; i++) { - cdns->response_buf[i] = cdns_readl(cdns, cmd_base); - cmd_base += CDNS_MCP_CMD_WORD_LEN; - } -} - static int cdns_update_slave_status(struct sdw_cdns *cdns, u64 slave_intstat) { From 1f800f6aae57d2d8f63d32fff383017cbc11cf65 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 28 Feb 2023 16:28:57 -0800 Subject: [PATCH 176/201] net: tls: avoid hanging tasks on the tx_lock commit f3221361dc85d4de22586ce8441ec2c67b454f5d upstream. syzbot sent a hung task report and Eric explains that adversarial receiver may keep RWIN at 0 for a long time, so we are not guaranteed to make forward progress. Thread which took tx_lock and went to sleep may not release tx_lock for hours. Use interruptible sleep where possible and reschedule the work if it can't take the lock. Testing: existing selftest passes Reported-by: syzbot+9c0268252b8ef967c62e@syzkaller.appspotmail.com Fixes: 79ffe6087e91 ("net/tls: add a TX lock") Link: https://lore.kernel.org/all/000000000000e412e905f5b46201@google.com/ Cc: stable@vger.kernel.org # wait 4 weeks Reviewed-by: Eric Dumazet Link: https://lore.kernel.org/r/20230301002857.2101894-1-kuba@kernel.org Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- net/tls/tls_sw.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index a83d2b4275fa..38dcd9b40102 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -941,7 +941,9 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) MSG_CMSG_COMPAT)) return -EOPNOTSUPP; - mutex_lock(&tls_ctx->tx_lock); + ret = mutex_lock_interruptible(&tls_ctx->tx_lock); + if (ret) + return ret; lock_sock(sk); if (unlikely(msg->msg_controllen)) { @@ -1275,7 +1277,9 @@ int tls_sw_sendpage(struct sock *sk, struct page *page, MSG_SENDPAGE_NOTLAST | MSG_SENDPAGE_NOPOLICY)) return -EOPNOTSUPP; - mutex_lock(&tls_ctx->tx_lock); + ret = mutex_lock_interruptible(&tls_ctx->tx_lock); + if (ret) + return ret; lock_sock(sk); ret = tls_sw_do_sendpage(sk, page, offset, size, flags); release_sock(sk); @@ -2416,11 +2420,19 @@ static void tx_work_handler(struct work_struct *work) if (!test_and_clear_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask)) return; - mutex_lock(&tls_ctx->tx_lock); - lock_sock(sk); - tls_tx_records(sk, -1); - release_sock(sk); - mutex_unlock(&tls_ctx->tx_lock); + + if (mutex_trylock(&tls_ctx->tx_lock)) { + lock_sock(sk); + tls_tx_records(sk, -1); + release_sock(sk); + mutex_unlock(&tls_ctx->tx_lock); + } else if (!test_and_set_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask)) { + /* Someone is holding the tx_lock, they will likely run Tx + * and cancel the work on their way out of the lock section. + * Schedule a long delay just in case. + */ + schedule_delayed_work(&ctx->tx_work.work, msecs_to_jiffies(10)); + } } static bool tls_is_tx_ready(struct tls_sw_context_tx *ctx) From 7ec0076b424ee3d6567d6cca7c3766af3bc33d4e Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 7 Mar 2023 13:06:29 -0800 Subject: [PATCH 177/201] x86/resctl: fix scheduler confusion with 'current' commit 7fef099702527c3b2c5234a2ea6a24411485a13a upstream. The implementation of 'current' on x86 is very intentionally special: it is a very common thing to look up, and it uses 'this_cpu_read_stable()' to get the current thread pointer efficiently from per-cpu storage. And the keyword in there is 'stable': the current thread pointer never changes as far as a single thread is concerned. Even if when a thread is preempted, or moved to another CPU, or even across an explicit call 'schedule()' that thread will still have the same value for 'current'. It is, after all, the kernel base pointer to thread-local storage. That's why it's stable to begin with, but it's also why it's important enough that we have that special 'this_cpu_read_stable()' access for it. So this is all done very intentionally to allow the compiler to treat 'current' as a value that never visibly changes, so that the compiler can do CSE and combine multiple different 'current' accesses into one. However, there is obviously one very special situation when the currently running thread does actually change: inside the scheduler itself. So the scheduler code paths are special, and do not have a 'current' thread at all. Instead there are _two_ threads: the previous and the next thread - typically called 'prev' and 'next' (or prev_p/next_p) internally. So this is all actually quite straightforward and simple, and not all that complicated. Except for when you then have special code that is run in scheduler context, that code then has to be aware that 'current' isn't really a valid thing. Did you mean 'prev'? Did you mean 'next'? In fact, even if then look at the code, and you use 'current' after the new value has been assigned to the percpu variable, we have explicitly told the compiler that 'current' is magical and always stable. So the compiler is quite free to use an older (or newer) value of 'current', and the actual assignment to the percpu storage is not relevant even if it might look that way. Which is exactly what happened in the resctl code, that blithely used 'current' in '__resctrl_sched_in()' when it really wanted the new process state (as implied by the name: we're scheduling 'into' that new resctl state). And clang would end up just using the old thread pointer value at least in some configurations. This could have happened with gcc too, and purely depends on random compiler details. Clang just seems to have been more aggressive about moving the read of the per-cpu current_task pointer around. The fix is trivial: just make the resctl code adhere to the scheduler rules of using the prev/next thread pointer explicitly, instead of using 'current' in a situation where it just wasn't valid. That same code is then also used outside of the scheduler context (when a thread resctl state is explicitly changed), and then we will just pass in 'current' as that pointer, of course. There is no ambiguity in that case. The fix may be trivial, but noticing and figuring out what went wrong was not. The credit for that goes to Stephane Eranian. Reported-by: Stephane Eranian Link: https://lore.kernel.org/lkml/20230303231133.1486085-1-eranian@google.com/ Link: https://lore.kernel.org/lkml/alpine.LFD.2.01.0908011214330.3304@localhost.localdomain/ Reviewed-by: Nick Desaulniers Tested-by: Tony Luck Tested-by: Stephane Eranian Tested-by: Babu Moger Cc: stable@kernel.org Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/resctrl.h | 12 ++++++------ arch/x86/kernel/cpu/resctrl/rdtgroup.c | 4 ++-- arch/x86/kernel/process_32.c | 2 +- arch/x86/kernel/process_64.c | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/x86/include/asm/resctrl.h b/arch/x86/include/asm/resctrl.h index d24b04ebf950..a4641d68eaba 100644 --- a/arch/x86/include/asm/resctrl.h +++ b/arch/x86/include/asm/resctrl.h @@ -51,7 +51,7 @@ DECLARE_STATIC_KEY_FALSE(rdt_mon_enable_key); * simple as possible. * Must be called with preemption disabled. */ -static void __resctrl_sched_in(void) +static inline void __resctrl_sched_in(struct task_struct *tsk) { struct resctrl_pqr_state *state = this_cpu_ptr(&pqr_state); u32 closid = state->default_closid; @@ -63,13 +63,13 @@ static void __resctrl_sched_in(void) * Else use the closid/rmid assigned to this cpu. */ if (static_branch_likely(&rdt_alloc_enable_key)) { - tmp = READ_ONCE(current->closid); + tmp = READ_ONCE(tsk->closid); if (tmp) closid = tmp; } if (static_branch_likely(&rdt_mon_enable_key)) { - tmp = READ_ONCE(current->rmid); + tmp = READ_ONCE(tsk->rmid); if (tmp) rmid = tmp; } @@ -90,17 +90,17 @@ static inline unsigned int resctrl_arch_round_mon_val(unsigned int val) return val * scale; } -static inline void resctrl_sched_in(void) +static inline void resctrl_sched_in(struct task_struct *tsk) { if (static_branch_likely(&rdt_enable_key)) - __resctrl_sched_in(); + __resctrl_sched_in(tsk); } void resctrl_cpu_detect(struct cpuinfo_x86 *c); #else -static inline void resctrl_sched_in(void) {} +static inline void resctrl_sched_in(struct task_struct *tsk) {} static inline void resctrl_cpu_detect(struct cpuinfo_x86 *c) {} #endif /* CONFIG_X86_CPU_RESCTRL */ diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c index 5993da21d822..87b670d540b8 100644 --- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c +++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c @@ -314,7 +314,7 @@ static void update_cpu_closid_rmid(void *info) * executing task might have its own closid selected. Just reuse * the context switch code. */ - resctrl_sched_in(); + resctrl_sched_in(current); } /* @@ -535,7 +535,7 @@ static void _update_task_closid_rmid(void *task) * Otherwise, the MSR is updated when the task is scheduled in. */ if (task == current) - resctrl_sched_in(); + resctrl_sched_in(task); } static void update_task_closid_rmid(struct task_struct *t) diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 2f314b170c9f..ceab14b6118f 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@ -212,7 +212,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) switch_fpu_finish(); /* Load the Intel cache allocation PQR MSR. */ - resctrl_sched_in(); + resctrl_sched_in(next_p); return prev_p; } diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 6b3418bff326..7f94dbbc397b 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -656,7 +656,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) } /* Load the Intel cache allocation PQR MSR. */ - resctrl_sched_in(); + resctrl_sched_in(next_p); return prev_p; } From 447d1c9abc844e2003ac0240e20822e0db0a37b9 Mon Sep 17 00:00:00 2001 From: Zhu Lingshan Date: Fri, 25 Nov 2022 22:57:13 +0800 Subject: [PATCH 178/201] vDPA/ifcvf: decouple hw features manipulators from the adapter commit d59f633dd05940739b5f46f5d4403cafb91d2742 upstream. This commit gets rid of ifcvf_adapter in hw features related functions in ifcvf_base. Then these functions are more rubust and de-coupling from the ifcvf_adapter layer. So these functions could be invoded once the device is probed, even before the adapter is allocaed. Signed-off-by: Zhu Lingshan Cc: stable@vger.kernel.org Message-Id: <20221125145724.1129962-2-lingshan.zhu@intel.com> Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/vdpa/ifcvf/ifcvf_base.c | 9 ++------- drivers/vdpa/ifcvf/ifcvf_base.h | 1 + drivers/vdpa/ifcvf/ifcvf_main.c | 1 + 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/vdpa/ifcvf/ifcvf_base.c b/drivers/vdpa/ifcvf/ifcvf_base.c index 3e4486bfa0b7..7a7e6ba66f88 100644 --- a/drivers/vdpa/ifcvf/ifcvf_base.c +++ b/drivers/vdpa/ifcvf/ifcvf_base.c @@ -220,10 +220,8 @@ u64 ifcvf_get_features(struct ifcvf_hw *hw) int ifcvf_verify_min_features(struct ifcvf_hw *hw, u64 features) { - struct ifcvf_adapter *ifcvf = vf_to_adapter(hw); - if (!(features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM)) && features) { - IFCVF_ERR(ifcvf->pdev, "VIRTIO_F_ACCESS_PLATFORM is not negotiated\n"); + IFCVF_ERR(hw->pdev, "VIRTIO_F_ACCESS_PLATFORM is not negotiated\n"); return -EINVAL; } @@ -301,14 +299,11 @@ static void ifcvf_set_features(struct ifcvf_hw *hw, u64 features) static int ifcvf_config_features(struct ifcvf_hw *hw) { - struct ifcvf_adapter *ifcvf; - - ifcvf = vf_to_adapter(hw); ifcvf_set_features(hw, hw->req_features); ifcvf_add_status(hw, VIRTIO_CONFIG_S_FEATURES_OK); if (!(ifcvf_get_status(hw) & VIRTIO_CONFIG_S_FEATURES_OK)) { - IFCVF_ERR(ifcvf->pdev, "Failed to set FEATURES_OK status\n"); + IFCVF_ERR(hw->pdev, "Failed to set FEATURES_OK status\n"); return -EIO; } diff --git a/drivers/vdpa/ifcvf/ifcvf_base.h b/drivers/vdpa/ifcvf/ifcvf_base.h index f5563f665cc6..e1fe947d61b7 100644 --- a/drivers/vdpa/ifcvf/ifcvf_base.h +++ b/drivers/vdpa/ifcvf/ifcvf_base.h @@ -89,6 +89,7 @@ struct ifcvf_hw { u16 nr_vring; /* VIRTIO_PCI_CAP_DEVICE_CFG size */ u32 cap_dev_config_size; + struct pci_dev *pdev; }; struct ifcvf_adapter { diff --git a/drivers/vdpa/ifcvf/ifcvf_main.c b/drivers/vdpa/ifcvf/ifcvf_main.c index 44b29289aa19..7383918b5719 100644 --- a/drivers/vdpa/ifcvf/ifcvf_main.c +++ b/drivers/vdpa/ifcvf/ifcvf_main.c @@ -842,6 +842,7 @@ static int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id) vf = &adapter->vf; vf->dev_type = get_dev_type(pdev); vf->base = pcim_iomap_table(pdev); + vf->pdev = pdev; adapter->pdev = pdev; adapter->vdpa.dma_dev = &pdev->dev; From 50da55ec0f04b2f1b20587442bd7b6c0810ab00d Mon Sep 17 00:00:00 2001 From: Zhu Lingshan Date: Fri, 25 Nov 2022 22:57:14 +0800 Subject: [PATCH 179/201] vDPA/ifcvf: decouple config space ops from the adapter commit af8eb69a62b73a2ce5f91575453534ac07f06eb4 upstream. This commit decopules the config space ops from the adapter layer, so these functions can be invoked once the device is probed. Signed-off-by: Zhu Lingshan Cc: stable@vger.kernel.org Message-Id: <20221125145724.1129962-3-lingshan.zhu@intel.com> Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/vdpa/ifcvf/ifcvf_base.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/drivers/vdpa/ifcvf/ifcvf_base.c b/drivers/vdpa/ifcvf/ifcvf_base.c index 7a7e6ba66f88..3ec5ca3aefe1 100644 --- a/drivers/vdpa/ifcvf/ifcvf_base.c +++ b/drivers/vdpa/ifcvf/ifcvf_base.c @@ -10,11 +10,6 @@ #include "ifcvf_base.h" -struct ifcvf_adapter *vf_to_adapter(struct ifcvf_hw *hw) -{ - return container_of(hw, struct ifcvf_adapter, vf); -} - u16 ifcvf_set_vq_vector(struct ifcvf_hw *hw, u16 qid, int vector) { struct virtio_pci_common_cfg __iomem *cfg = hw->common_cfg; @@ -37,8 +32,6 @@ u16 ifcvf_set_config_vector(struct ifcvf_hw *hw, int vector) static void __iomem *get_cap_addr(struct ifcvf_hw *hw, struct virtio_pci_cap *cap) { - struct ifcvf_adapter *ifcvf; - struct pci_dev *pdev; u32 length, offset; u8 bar; @@ -46,17 +39,14 @@ static void __iomem *get_cap_addr(struct ifcvf_hw *hw, offset = le32_to_cpu(cap->offset); bar = cap->bar; - ifcvf= vf_to_adapter(hw); - pdev = ifcvf->pdev; - if (bar >= IFCVF_PCI_MAX_RESOURCE) { - IFCVF_DBG(pdev, + IFCVF_DBG(hw->pdev, "Invalid bar number %u to get capabilities\n", bar); return NULL; } - if (offset + length > pci_resource_len(pdev, bar)) { - IFCVF_DBG(pdev, + if (offset + length > pci_resource_len(hw->pdev, bar)) { + IFCVF_DBG(hw->pdev, "offset(%u) + len(%u) overflows bar%u's capability\n", offset, length, bar); return NULL; @@ -92,6 +82,7 @@ int ifcvf_init_hw(struct ifcvf_hw *hw, struct pci_dev *pdev) IFCVF_ERR(pdev, "Failed to read PCI capability list\n"); return -EIO; } + hw->pdev = pdev; while (pos) { ret = ifcvf_read_config_range(pdev, (u32 *)&cap, @@ -230,13 +221,11 @@ int ifcvf_verify_min_features(struct ifcvf_hw *hw, u64 features) u32 ifcvf_get_config_size(struct ifcvf_hw *hw) { - struct ifcvf_adapter *adapter; u32 net_config_size = sizeof(struct virtio_net_config); u32 blk_config_size = sizeof(struct virtio_blk_config); u32 cap_size = hw->cap_dev_config_size; u32 config_size; - adapter = vf_to_adapter(hw); /* If the onboard device config space size is greater than * the size of struct virtio_net/blk_config, only the spec * implementing contents size is returned, this is very @@ -251,7 +240,7 @@ u32 ifcvf_get_config_size(struct ifcvf_hw *hw) break; default: config_size = 0; - IFCVF_ERR(adapter->pdev, "VIRTIO ID %u not supported\n", hw->dev_type); + IFCVF_ERR(hw->pdev, "VIRTIO ID %u not supported\n", hw->dev_type); } return config_size; From aa2af9353aeb574f6718b64c1e61de0b53257d7e Mon Sep 17 00:00:00 2001 From: Zhu Lingshan Date: Fri, 25 Nov 2022 22:57:15 +0800 Subject: [PATCH 180/201] vDPA/ifcvf: alloc the mgmt_dev before the adapter commit 66e3970b16d1e960afbece65739a3628273633f1 upstream. This commit reverses the order of allocating the management device and the adapter. So that it would be possible to move the allocation of the adapter to dev_add(). Signed-off-by: Zhu Lingshan Cc: stable@vger.kernel.org Message-Id: <20221125145724.1129962-4-lingshan.zhu@intel.com> Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/vdpa/ifcvf/ifcvf_main.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/drivers/vdpa/ifcvf/ifcvf_main.c b/drivers/vdpa/ifcvf/ifcvf_main.c index 7383918b5719..860f72bfa7ba 100644 --- a/drivers/vdpa/ifcvf/ifcvf_main.c +++ b/drivers/vdpa/ifcvf/ifcvf_main.c @@ -831,22 +831,30 @@ static int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id) } pci_set_master(pdev); + ifcvf_mgmt_dev = kzalloc(sizeof(struct ifcvf_vdpa_mgmt_dev), GFP_KERNEL); + if (!ifcvf_mgmt_dev) { + IFCVF_ERR(pdev, "Failed to alloc memory for the vDPA management device\n"); + return -ENOMEM; + } adapter = vdpa_alloc_device(struct ifcvf_adapter, vdpa, dev, &ifc_vdpa_ops, 1, 1, NULL, false); if (IS_ERR(adapter)) { IFCVF_ERR(pdev, "Failed to allocate vDPA structure"); - return PTR_ERR(adapter); + ret = PTR_ERR(adapter); + goto err; } + adapter->pdev = pdev; + adapter->vdpa.dma_dev = &pdev->dev; + adapter->vdpa.mdev = &ifcvf_mgmt_dev->mdev; + ifcvf_mgmt_dev->adapter = adapter; + vf = &adapter->vf; vf->dev_type = get_dev_type(pdev); vf->base = pcim_iomap_table(pdev); vf->pdev = pdev; - adapter->pdev = pdev; - adapter->vdpa.dma_dev = &pdev->dev; - ret = ifcvf_init_hw(vf, pdev); if (ret) { IFCVF_ERR(pdev, "Failed to init IFCVF hw\n"); @@ -859,16 +867,6 @@ static int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id) vf->hw_features = ifcvf_get_hw_features(vf); vf->config_size = ifcvf_get_config_size(vf); - ifcvf_mgmt_dev = kzalloc(sizeof(struct ifcvf_vdpa_mgmt_dev), GFP_KERNEL); - if (!ifcvf_mgmt_dev) { - IFCVF_ERR(pdev, "Failed to alloc memory for the vDPA management device\n"); - return -ENOMEM; - } - - ifcvf_mgmt_dev->mdev.ops = &ifcvf_vdpa_mgmt_dev_ops; - ifcvf_mgmt_dev->mdev.device = dev; - ifcvf_mgmt_dev->adapter = adapter; - dev_type = get_dev_type(pdev); switch (dev_type) { case VIRTIO_ID_NET: @@ -883,12 +881,11 @@ static int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err; } + ifcvf_mgmt_dev->mdev.ops = &ifcvf_vdpa_mgmt_dev_ops; + ifcvf_mgmt_dev->mdev.device = dev; ifcvf_mgmt_dev->mdev.max_supported_vqs = vf->nr_vring; ifcvf_mgmt_dev->mdev.supported_features = vf->hw_features; - adapter->vdpa.mdev = &ifcvf_mgmt_dev->mdev; - - ret = vdpa_mgmtdev_register(&ifcvf_mgmt_dev->mdev); if (ret) { IFCVF_ERR(pdev, From 62fb450c4dd2a4a1d861398c6e6300f53ab9afd8 Mon Sep 17 00:00:00 2001 From: Zhu Lingshan Date: Fri, 25 Nov 2022 22:57:16 +0800 Subject: [PATCH 181/201] vDPA/ifcvf: decouple vq IRQ releasers from the adapter commit 004cbcabab46d9346e2524c4eedd71ea57fe4f3c upstream. This commit decouples the IRQ releasers from the adapter, so that these functions could be safely invoked once probe Signed-off-by: Zhu Lingshan Cc: stable@vger.kernel.org Message-Id: <20221125145724.1129962-5-lingshan.zhu@intel.com> Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/vdpa/ifcvf/ifcvf_main.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/vdpa/ifcvf/ifcvf_main.c b/drivers/vdpa/ifcvf/ifcvf_main.c index 860f72bfa7ba..a96c0a38cce2 100644 --- a/drivers/vdpa/ifcvf/ifcvf_main.c +++ b/drivers/vdpa/ifcvf/ifcvf_main.c @@ -69,10 +69,9 @@ static void ifcvf_free_irq_vectors(void *data) pci_free_irq_vectors(data); } -static void ifcvf_free_per_vq_irq(struct ifcvf_adapter *adapter) +static void ifcvf_free_per_vq_irq(struct ifcvf_hw *vf) { - struct pci_dev *pdev = adapter->pdev; - struct ifcvf_hw *vf = &adapter->vf; + struct pci_dev *pdev = vf->pdev; int i; for (i = 0; i < vf->nr_vring; i++) { @@ -83,10 +82,9 @@ static void ifcvf_free_per_vq_irq(struct ifcvf_adapter *adapter) } } -static void ifcvf_free_vqs_reused_irq(struct ifcvf_adapter *adapter) +static void ifcvf_free_vqs_reused_irq(struct ifcvf_hw *vf) { - struct pci_dev *pdev = adapter->pdev; - struct ifcvf_hw *vf = &adapter->vf; + struct pci_dev *pdev = vf->pdev; if (vf->vqs_reused_irq != -EINVAL) { devm_free_irq(&pdev->dev, vf->vqs_reused_irq, vf); @@ -95,14 +93,12 @@ static void ifcvf_free_vqs_reused_irq(struct ifcvf_adapter *adapter) } -static void ifcvf_free_vq_irq(struct ifcvf_adapter *adapter) +static void ifcvf_free_vq_irq(struct ifcvf_hw *vf) { - struct ifcvf_hw *vf = &adapter->vf; - if (vf->msix_vector_status == MSIX_VECTOR_PER_VQ_AND_CONFIG) - ifcvf_free_per_vq_irq(adapter); + ifcvf_free_per_vq_irq(vf); else - ifcvf_free_vqs_reused_irq(adapter); + ifcvf_free_vqs_reused_irq(vf); } static void ifcvf_free_config_irq(struct ifcvf_adapter *adapter) @@ -126,8 +122,9 @@ static void ifcvf_free_config_irq(struct ifcvf_adapter *adapter) static void ifcvf_free_irq(struct ifcvf_adapter *adapter) { struct pci_dev *pdev = adapter->pdev; + struct ifcvf_hw *vf = &adapter->vf; - ifcvf_free_vq_irq(adapter); + ifcvf_free_vq_irq(vf); ifcvf_free_config_irq(adapter); ifcvf_free_irq_vectors(pdev); } From c0fca7704f5e8fa454a13956409227f1224c1427 Mon Sep 17 00:00:00 2001 From: Zhu Lingshan Date: Fri, 25 Nov 2022 22:57:17 +0800 Subject: [PATCH 182/201] vDPA/ifcvf: decouple config IRQ releaser from the adapter commit 23dac55cec3afdbc1b4eaed1c79f2cee00477f8b upstream. This commit decouples config IRQ releaser from the adapter, so that it could be invoked once probe or in err handlers. ifcvf_free_irq() works on ifcvf_hw in this commit Signed-off-by: Zhu Lingshan Cc: stable@vger.kernel.org Message-Id: <20221125145724.1129962-6-lingshan.zhu@intel.com> Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/vdpa/ifcvf/ifcvf_main.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/vdpa/ifcvf/ifcvf_main.c b/drivers/vdpa/ifcvf/ifcvf_main.c index a96c0a38cce2..7db007ba0dcf 100644 --- a/drivers/vdpa/ifcvf/ifcvf_main.c +++ b/drivers/vdpa/ifcvf/ifcvf_main.c @@ -101,10 +101,9 @@ static void ifcvf_free_vq_irq(struct ifcvf_hw *vf) ifcvf_free_vqs_reused_irq(vf); } -static void ifcvf_free_config_irq(struct ifcvf_adapter *adapter) +static void ifcvf_free_config_irq(struct ifcvf_hw *vf) { - struct pci_dev *pdev = adapter->pdev; - struct ifcvf_hw *vf = &adapter->vf; + struct pci_dev *pdev = vf->pdev; if (vf->config_irq == -EINVAL) return; @@ -119,13 +118,12 @@ static void ifcvf_free_config_irq(struct ifcvf_adapter *adapter) } } -static void ifcvf_free_irq(struct ifcvf_adapter *adapter) +static void ifcvf_free_irq(struct ifcvf_hw *vf) { - struct pci_dev *pdev = adapter->pdev; - struct ifcvf_hw *vf = &adapter->vf; + struct pci_dev *pdev = vf->pdev; ifcvf_free_vq_irq(vf); - ifcvf_free_config_irq(adapter); + ifcvf_free_config_irq(vf); ifcvf_free_irq_vectors(pdev); } @@ -187,7 +185,7 @@ static int ifcvf_request_per_vq_irq(struct ifcvf_adapter *adapter) return 0; err: - ifcvf_free_irq(adapter); + ifcvf_free_irq(vf); return -EFAULT; } @@ -221,7 +219,7 @@ static int ifcvf_request_vqs_reused_irq(struct ifcvf_adapter *adapter) return 0; err: - ifcvf_free_irq(adapter); + ifcvf_free_irq(vf); return -EFAULT; } @@ -262,7 +260,7 @@ static int ifcvf_request_dev_irq(struct ifcvf_adapter *adapter) return 0; err: - ifcvf_free_irq(adapter); + ifcvf_free_irq(vf); return -EFAULT; @@ -317,7 +315,7 @@ static int ifcvf_request_config_irq(struct ifcvf_adapter *adapter) return 0; err: - ifcvf_free_irq(adapter); + ifcvf_free_irq(vf); return -EFAULT; } @@ -508,7 +506,7 @@ static int ifcvf_vdpa_reset(struct vdpa_device *vdpa_dev) if (status_old & VIRTIO_CONFIG_S_DRIVER_OK) { ifcvf_stop_datapath(adapter); - ifcvf_free_irq(adapter); + ifcvf_free_irq(vf); } ifcvf_reset_vring(adapter); From e35beaa142d789a62fbeb923a2bc355447493c3d Mon Sep 17 00:00:00 2001 From: Zhu Lingshan Date: Fri, 25 Nov 2022 22:57:18 +0800 Subject: [PATCH 183/201] vDPA/ifcvf: decouple vq irq requester from the adapter commit f9a9ffb2e4dbde81090416fc51662441c2a7b73b upstream. This commit decouples the vq irq requester from the adapter, so that these functions can be invoked since probe. Signed-off-by: Zhu Lingshan Cc: stable@vger.kernel.org Message-Id: <20221125145724.1129962-7-lingshan.zhu@intel.com> Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/vdpa/ifcvf/ifcvf_main.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/vdpa/ifcvf/ifcvf_main.c b/drivers/vdpa/ifcvf/ifcvf_main.c index 7db007ba0dcf..8573804e3440 100644 --- a/drivers/vdpa/ifcvf/ifcvf_main.c +++ b/drivers/vdpa/ifcvf/ifcvf_main.c @@ -155,10 +155,9 @@ static int ifcvf_alloc_vectors(struct ifcvf_adapter *adapter) return ret; } -static int ifcvf_request_per_vq_irq(struct ifcvf_adapter *adapter) +static int ifcvf_request_per_vq_irq(struct ifcvf_hw *vf) { - struct pci_dev *pdev = adapter->pdev; - struct ifcvf_hw *vf = &adapter->vf; + struct pci_dev *pdev = vf->pdev; int i, vector, ret, irq; vf->vqs_reused_irq = -EINVAL; @@ -190,10 +189,9 @@ err: return -EFAULT; } -static int ifcvf_request_vqs_reused_irq(struct ifcvf_adapter *adapter) +static int ifcvf_request_vqs_reused_irq(struct ifcvf_hw *vf) { - struct pci_dev *pdev = adapter->pdev; - struct ifcvf_hw *vf = &adapter->vf; + struct pci_dev *pdev = vf->pdev; int i, vector, ret, irq; vector = 0; @@ -266,15 +264,14 @@ err: } -static int ifcvf_request_vq_irq(struct ifcvf_adapter *adapter) +static int ifcvf_request_vq_irq(struct ifcvf_hw *vf) { - struct ifcvf_hw *vf = &adapter->vf; int ret; if (vf->msix_vector_status == MSIX_VECTOR_PER_VQ_AND_CONFIG) - ret = ifcvf_request_per_vq_irq(adapter); + ret = ifcvf_request_per_vq_irq(vf); else - ret = ifcvf_request_vqs_reused_irq(adapter); + ret = ifcvf_request_vqs_reused_irq(vf); return ret; } @@ -341,7 +338,7 @@ static int ifcvf_request_irq(struct ifcvf_adapter *adapter) return ret; } - ret = ifcvf_request_vq_irq(adapter); + ret = ifcvf_request_vq_irq(vf); if (ret) return ret; From 154c0aea566dcdfd7c0dd8da83454c3eca1f0962 Mon Sep 17 00:00:00 2001 From: Zhu Lingshan Date: Fri, 25 Nov 2022 22:57:19 +0800 Subject: [PATCH 184/201] vDPA/ifcvf: decouple config/dev IRQ requester and vectors allocator from the adapter commit a70d833e696e538a0feff5e539086c74a90ddf90 upstream. This commit decouples the config irq requester, the device shared irq requester and the MSI vectors allocator from the adapter. So they can be safely invoked since probe before the adapter is allocated. Signed-off-by: Zhu Lingshan Cc: stable@vger.kernel.org Message-Id: <20221125145724.1129962-8-lingshan.zhu@intel.com> Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/vdpa/ifcvf/ifcvf_main.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/vdpa/ifcvf/ifcvf_main.c b/drivers/vdpa/ifcvf/ifcvf_main.c index 8573804e3440..6fcc412b46de 100644 --- a/drivers/vdpa/ifcvf/ifcvf_main.c +++ b/drivers/vdpa/ifcvf/ifcvf_main.c @@ -132,10 +132,9 @@ static void ifcvf_free_irq(struct ifcvf_hw *vf) * It returns the number of allocated vectors, negative * return value when fails. */ -static int ifcvf_alloc_vectors(struct ifcvf_adapter *adapter) +static int ifcvf_alloc_vectors(struct ifcvf_hw *vf) { - struct pci_dev *pdev = adapter->pdev; - struct ifcvf_hw *vf = &adapter->vf; + struct pci_dev *pdev = vf->pdev; int max_intr, ret; /* all queues and config interrupt */ @@ -222,10 +221,9 @@ err: return -EFAULT; } -static int ifcvf_request_dev_irq(struct ifcvf_adapter *adapter) +static int ifcvf_request_dev_irq(struct ifcvf_hw *vf) { - struct pci_dev *pdev = adapter->pdev; - struct ifcvf_hw *vf = &adapter->vf; + struct pci_dev *pdev = vf->pdev; int i, vector, ret, irq; vector = 0; @@ -276,10 +274,9 @@ static int ifcvf_request_vq_irq(struct ifcvf_hw *vf) return ret; } -static int ifcvf_request_config_irq(struct ifcvf_adapter *adapter) +static int ifcvf_request_config_irq(struct ifcvf_hw *vf) { - struct pci_dev *pdev = adapter->pdev; - struct ifcvf_hw *vf = &adapter->vf; + struct pci_dev *pdev = vf->pdev; int config_vector, ret; if (vf->msix_vector_status == MSIX_VECTOR_PER_VQ_AND_CONFIG) @@ -322,7 +319,7 @@ static int ifcvf_request_irq(struct ifcvf_adapter *adapter) struct ifcvf_hw *vf = &adapter->vf; int nvectors, ret, max_intr; - nvectors = ifcvf_alloc_vectors(adapter); + nvectors = ifcvf_alloc_vectors(vf); if (nvectors <= 0) return -EFAULT; @@ -333,7 +330,7 @@ static int ifcvf_request_irq(struct ifcvf_adapter *adapter) if (nvectors == 1) { vf->msix_vector_status = MSIX_VECTOR_DEV_SHARED; - ret = ifcvf_request_dev_irq(adapter); + ret = ifcvf_request_dev_irq(vf); return ret; } @@ -342,7 +339,7 @@ static int ifcvf_request_irq(struct ifcvf_adapter *adapter) if (ret) return ret; - ret = ifcvf_request_config_irq(adapter); + ret = ifcvf_request_config_irq(vf); if (ret) return ret; From 6ddb3b8058279bad93f96be4b04480a893b0d171 Mon Sep 17 00:00:00 2001 From: Zhu Lingshan Date: Fri, 25 Nov 2022 22:57:20 +0800 Subject: [PATCH 185/201] vDPA/ifcvf: ifcvf_request_irq works on ifcvf_hw commit 7cfd36b7e8be6bdaeb5af0f9729871b732a7a3c8 upstream. All ifcvf_request_irq's callees are refactored to work on ifcvf_hw, so it should be decoupled from the adapter as well Signed-off-by: Zhu Lingshan Cc: stable@vger.kernel.org Message-Id: <20221125145724.1129962-9-lingshan.zhu@intel.com> Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/vdpa/ifcvf/ifcvf_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/vdpa/ifcvf/ifcvf_main.c b/drivers/vdpa/ifcvf/ifcvf_main.c index 6fcc412b46de..a09a1c26b714 100644 --- a/drivers/vdpa/ifcvf/ifcvf_main.c +++ b/drivers/vdpa/ifcvf/ifcvf_main.c @@ -314,9 +314,8 @@ err: return -EFAULT; } -static int ifcvf_request_irq(struct ifcvf_adapter *adapter) +static int ifcvf_request_irq(struct ifcvf_hw *vf) { - struct ifcvf_hw *vf = &adapter->vf; int nvectors, ret, max_intr; nvectors = ifcvf_alloc_vectors(vf); @@ -468,7 +467,7 @@ static void ifcvf_vdpa_set_status(struct vdpa_device *vdpa_dev, u8 status) if ((status & VIRTIO_CONFIG_S_DRIVER_OK) && !(status_old & VIRTIO_CONFIG_S_DRIVER_OK)) { - ret = ifcvf_request_irq(adapter); + ret = ifcvf_request_irq(vf); if (ret) { status = ifcvf_get_status(vf); status |= VIRTIO_CONFIG_S_FAILED; From dd5d2d8821b2afda55219742b418369fa23b57f2 Mon Sep 17 00:00:00 2001 From: Zhu Lingshan Date: Fri, 25 Nov 2022 22:57:21 +0800 Subject: [PATCH 186/201] vDPA/ifcvf: manage ifcvf_hw in the mgmt_dev commit 6a3b2f179b49f2c6452ecc37b4778a43848b454c upstream. This commit allocates the hw structure in the management device structure. So the hardware can be initialized once the management device is allocated in probe. Signed-off-by: Zhu Lingshan Cc: stable@vger.kernel.org Message-Id: <20221125145724.1129962-10-lingshan.zhu@intel.com> Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/vdpa/ifcvf/ifcvf_base.h | 5 +++-- drivers/vdpa/ifcvf/ifcvf_main.c | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/vdpa/ifcvf/ifcvf_base.h b/drivers/vdpa/ifcvf/ifcvf_base.h index e1fe947d61b7..25bd4e927b27 100644 --- a/drivers/vdpa/ifcvf/ifcvf_base.h +++ b/drivers/vdpa/ifcvf/ifcvf_base.h @@ -39,7 +39,7 @@ #define IFCVF_INFO(pdev, fmt, ...) dev_info(&pdev->dev, fmt, ##__VA_ARGS__) #define ifcvf_private_to_vf(adapter) \ - (&((struct ifcvf_adapter *)adapter)->vf) + (((struct ifcvf_adapter *)adapter)->vf) /* all vqs and config interrupt has its own vector */ #define MSIX_VECTOR_PER_VQ_AND_CONFIG 1 @@ -95,7 +95,7 @@ struct ifcvf_hw { struct ifcvf_adapter { struct vdpa_device vdpa; struct pci_dev *pdev; - struct ifcvf_hw vf; + struct ifcvf_hw *vf; }; struct ifcvf_vring_lm_cfg { @@ -110,6 +110,7 @@ struct ifcvf_lm_cfg { struct ifcvf_vdpa_mgmt_dev { struct vdpa_mgmt_dev mdev; + struct ifcvf_hw vf; struct ifcvf_adapter *adapter; struct pci_dev *pdev; }; diff --git a/drivers/vdpa/ifcvf/ifcvf_main.c b/drivers/vdpa/ifcvf/ifcvf_main.c index a09a1c26b714..5f1d81ad2fbe 100644 --- a/drivers/vdpa/ifcvf/ifcvf_main.c +++ b/drivers/vdpa/ifcvf/ifcvf_main.c @@ -402,7 +402,7 @@ static struct ifcvf_hw *vdpa_to_vf(struct vdpa_device *vdpa_dev) { struct ifcvf_adapter *adapter = vdpa_to_adapter(vdpa_dev); - return &adapter->vf; + return adapter->vf; } static u64 ifcvf_vdpa_get_device_features(struct vdpa_device *vdpa_dev) @@ -750,7 +750,7 @@ static int ifcvf_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, return -EOPNOTSUPP; adapter = ifcvf_mgmt_dev->adapter; - vf = &adapter->vf; + vf = adapter->vf; pdev = adapter->pdev; vdpa_dev = &adapter->vdpa; @@ -838,10 +838,11 @@ static int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id) adapter->vdpa.mdev = &ifcvf_mgmt_dev->mdev; ifcvf_mgmt_dev->adapter = adapter; - vf = &adapter->vf; + vf = &ifcvf_mgmt_dev->vf; vf->dev_type = get_dev_type(pdev); vf->base = pcim_iomap_table(pdev); vf->pdev = pdev; + adapter->vf = vf; ret = ifcvf_init_hw(vf, pdev); if (ret) { From beb15de99ae8fb4d270cb9b55509b72826a1b63d Mon Sep 17 00:00:00 2001 From: Zhu Lingshan Date: Fri, 25 Nov 2022 22:57:22 +0800 Subject: [PATCH 187/201] vDPA/ifcvf: allocate the adapter in dev_add() commit 93139037b582134deb1ed894bbc4bc1d34ff35e7 upstream. The adapter is the container of the vdpa_device, this commits allocate the adapter in dev_add() rather than in probe(). So that the vdpa_device() could be re-created when the userspace creates the vdpa device, and free-ed in dev_del() Signed-off-by: Zhu Lingshan Cc: stable@vger.kernel.org Message-Id: <20221125145724.1129962-11-lingshan.zhu@intel.com> Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/vdpa/ifcvf/ifcvf_main.c | 34 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/drivers/vdpa/ifcvf/ifcvf_main.c b/drivers/vdpa/ifcvf/ifcvf_main.c index 5f1d81ad2fbe..d5036f49f161 100644 --- a/drivers/vdpa/ifcvf/ifcvf_main.c +++ b/drivers/vdpa/ifcvf/ifcvf_main.c @@ -746,12 +746,20 @@ static int ifcvf_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, int ret; ifcvf_mgmt_dev = container_of(mdev, struct ifcvf_vdpa_mgmt_dev, mdev); - if (!ifcvf_mgmt_dev->adapter) - return -EOPNOTSUPP; + vf = &ifcvf_mgmt_dev->vf; + pdev = vf->pdev; + adapter = vdpa_alloc_device(struct ifcvf_adapter, vdpa, + &pdev->dev, &ifc_vdpa_ops, 1, 1, NULL, false); + if (IS_ERR(adapter)) { + IFCVF_ERR(pdev, "Failed to allocate vDPA structure"); + return PTR_ERR(adapter); + } - adapter = ifcvf_mgmt_dev->adapter; - vf = adapter->vf; - pdev = adapter->pdev; + ifcvf_mgmt_dev->adapter = adapter; + adapter->pdev = pdev; + adapter->vdpa.dma_dev = &pdev->dev; + adapter->vdpa.mdev = mdev; + adapter->vf = vf; vdpa_dev = &adapter->vdpa; if (name) @@ -769,7 +777,6 @@ static int ifcvf_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name, return 0; } - static void ifcvf_vdpa_dev_del(struct vdpa_mgmt_dev *mdev, struct vdpa_device *dev) { struct ifcvf_vdpa_mgmt_dev *ifcvf_mgmt_dev; @@ -788,7 +795,6 @@ static int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct ifcvf_vdpa_mgmt_dev *ifcvf_mgmt_dev; struct device *dev = &pdev->dev; - struct ifcvf_adapter *adapter; struct ifcvf_hw *vf; u32 dev_type; int ret, i; @@ -825,24 +831,10 @@ static int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -ENOMEM; } - adapter = vdpa_alloc_device(struct ifcvf_adapter, vdpa, - dev, &ifc_vdpa_ops, 1, 1, NULL, false); - if (IS_ERR(adapter)) { - IFCVF_ERR(pdev, "Failed to allocate vDPA structure"); - ret = PTR_ERR(adapter); - goto err; - } - - adapter->pdev = pdev; - adapter->vdpa.dma_dev = &pdev->dev; - adapter->vdpa.mdev = &ifcvf_mgmt_dev->mdev; - ifcvf_mgmt_dev->adapter = adapter; - vf = &ifcvf_mgmt_dev->vf; vf->dev_type = get_dev_type(pdev); vf->base = pcim_iomap_table(pdev); vf->pdev = pdev; - adapter->vf = vf; ret = ifcvf_init_hw(vf, pdev); if (ret) { From 6130b22fb677430af8fe4a2ac4fbf2f5b8572d12 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 6 Feb 2023 13:48:55 +0200 Subject: [PATCH 188/201] drm/display/dp_mst: Add drm_atomic_get_old_mst_topology_state() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 9ffdb67af0ee625ae127711845532f670cc6a4e7 upstream. Add a function to get the old MST topology state, required by a follow-up i915 patch. While at it clarify the code comment of drm_atomic_get_new_mst_topology_state() and add _new prefix to the new state pointer to remind about its difference from the old state. v2: Use old_/new_ prefixes for the state pointers. (Ville) Cc: Lyude Paul Cc: Ville Syrjälä Cc: stable@vger.kernel.org # 6.1 Cc: dri-devel@lists.freedesktop.org Reviewed-by: Ville Syrjälä Reviewed-by: Lyude Paul Acked-by: Lyude Paul Acked-by: Daniel Vetter Acked-by: Wayne Lin Acked-by: Jani Nikula Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20230206114856.2665066-3-imre.deak@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/display/drm_dp_mst_topology.c | 35 ++++++++++++++++--- include/drm/display/drm_dp_mst_helper.h | 3 ++ 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index 4ca37261584a..7e7364c69d9f 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -5355,27 +5355,52 @@ struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_a EXPORT_SYMBOL(drm_atomic_get_mst_topology_state); /** - * drm_atomic_get_new_mst_topology_state: get new MST topology state in atomic state, if any + * drm_atomic_get_old_mst_topology_state: get old MST topology state in atomic state, if any * @state: global atomic state * @mgr: MST topology manager, also the private object in this case * - * This function wraps drm_atomic_get_priv_obj_state() passing in the MST atomic + * This function wraps drm_atomic_get_old_private_obj_state() passing in the MST atomic * state vtable so that the private object state returned is that of a MST * topology object. * * Returns: * - * The MST topology state, or NULL if there's no topology state for this MST mgr + * The old MST topology state, or NULL if there's no topology state for this MST mgr + * in the global atomic state + */ +struct drm_dp_mst_topology_state * +drm_atomic_get_old_mst_topology_state(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr) +{ + struct drm_private_state *old_priv_state = + drm_atomic_get_old_private_obj_state(state, &mgr->base); + + return old_priv_state ? to_dp_mst_topology_state(old_priv_state) : NULL; +} +EXPORT_SYMBOL(drm_atomic_get_old_mst_topology_state); + +/** + * drm_atomic_get_new_mst_topology_state: get new MST topology state in atomic state, if any + * @state: global atomic state + * @mgr: MST topology manager, also the private object in this case + * + * This function wraps drm_atomic_get_new_private_obj_state() passing in the MST atomic + * state vtable so that the private object state returned is that of a MST + * topology object. + * + * Returns: + * + * The new MST topology state, or NULL if there's no topology state for this MST mgr * in the global atomic state */ struct drm_dp_mst_topology_state * drm_atomic_get_new_mst_topology_state(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr) { - struct drm_private_state *priv_state = + struct drm_private_state *new_priv_state = drm_atomic_get_new_private_obj_state(state, &mgr->base); - return priv_state ? to_dp_mst_topology_state(priv_state) : NULL; + return new_priv_state ? to_dp_mst_topology_state(new_priv_state) : NULL; } EXPORT_SYMBOL(drm_atomic_get_new_mst_topology_state); diff --git a/include/drm/display/drm_dp_mst_helper.h b/include/drm/display/drm_dp_mst_helper.h index 41fd8352ab65..6c0c3dc3d3ac 100644 --- a/include/drm/display/drm_dp_mst_helper.h +++ b/include/drm/display/drm_dp_mst_helper.h @@ -867,6 +867,9 @@ struct drm_dp_mst_topology_state * drm_atomic_get_mst_topology_state(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr); struct drm_dp_mst_topology_state * +drm_atomic_get_old_mst_topology_state(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr); +struct drm_dp_mst_topology_state * drm_atomic_get_new_mst_topology_state(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr); struct drm_dp_mst_atomic_payload * From b30fcedeba643ca16eaa6212c1245598b7cd830d Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 14 Dec 2022 20:42:56 +0200 Subject: [PATCH 189/201] drm/display/dp_mst: Fix down/up message handling after sink disconnect commit 1d082618bbf3b6755b8cc68c0a8122af2842d593 upstream. If the sink gets disconnected during receiving a multi-packet DP MST AUX down-reply/up-request sideband message, the state keeping track of which packets have been received already is not reset. This results in a failed sanity check for the subsequent message packet received after a sink is reconnected (due to the pending message not yet completed with an end-of-message-transfer packet), indicated by the "sideband msg set header failed" error. Fix the above by resetting the up/down message reception state after a disconnect event. Cc: Lyude Paul Cc: # v3.17+ Signed-off-by: Imre Deak Reviewed-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20221214184258.2869417-1-imre.deak@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/display/drm_dp_mst_topology.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index 7e7364c69d9f..82d1473af2d9 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -3644,6 +3644,9 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, 0); ret = 0; mgr->payload_id_table_cleared = false; + + memset(&mgr->down_rep_recv, 0, sizeof(mgr->down_rep_recv)); + memset(&mgr->up_req_recv, 0, sizeof(mgr->up_req_recv)); } out_unlock: From efe5ce019a9bae988ac244b593da21cec30e9c06 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 14 Dec 2022 20:42:57 +0200 Subject: [PATCH 190/201] drm/display/dp_mst: Fix down message handling after a packet reception error commit 1241aedb6b5c7a5a8ad73e5eb3a41cfe18a3e00e upstream. After an error during receiving a packet for a multi-packet DP MST sideband message, the state tracking which packets have been received already is not reset. This prevents the reception of subsequent down messages (due to the pending message not yet completed with an end-of-message-transfer packet). Fix the above by resetting the reception state after a packet error. Cc: Lyude Paul Cc: # v3.17+ Signed-off-by: Imre Deak Reviewed-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20221214184258.2869417-2-imre.deak@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/display/drm_dp_mst_topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index 82d1473af2d9..d77858c7c4db 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -3859,7 +3859,7 @@ static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr) struct drm_dp_sideband_msg_rx *msg = &mgr->down_rep_recv; if (!drm_dp_get_one_sb_msg(mgr, false, &mstb)) - goto out; + goto out_clear_reply; /* Multi-packet message transmission, don't clear the reply */ if (!msg->have_eomt) From 6e48e7901e6258b8ea1116d70752d0eb2eca797d Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 14 Dec 2022 20:42:58 +0200 Subject: [PATCH 191/201] drm/display/dp_mst: Fix payload addition on a disconnected sink commit 33f960e23c29d113fe3193e0bdc19ac4f3776f20 upstream. If an MST stream is enabled on a disconnected sink, the payload for the stream is not created and the MST manager's payload count/next start VC slot is not updated. Since the payload's start VC slot may still contain a valid value (!= -1) the subsequent disabling of such a stream could cause an incorrect decrease of the payload count/next start VC slot in drm_dp_remove_payload() and hence later payload additions will fail. Fix the above by marking the payload as invalid in the above case, so that it's skipped during payload removal. While at it add a debug print for this case. Cc: Lyude Paul Cc: # v6.1+ Signed-off-by: Imre Deak Reviewed-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20221214184258.2869417-3-imre.deak@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/display/drm_dp_mst_topology.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index d77858c7c4db..e77c674b37ca 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -3309,8 +3309,13 @@ int drm_dp_add_payload_part1(struct drm_dp_mst_topology_mgr *mgr, int ret; port = drm_dp_mst_topology_get_port_validated(mgr, payload->port); - if (!port) + if (!port) { + drm_dbg_kms(mgr->dev, + "VCPI %d for port %p not in topology, not creating a payload\n", + payload->vcpi, payload->port); + payload->vc_start_slot = -1; return 0; + } if (mgr->payload_count == 0) mgr->next_start_slot = mst_state->start_slot; From fb5f2b42650f60a06cfe794e40810c22083c171a Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 6 Feb 2023 13:48:53 +0200 Subject: [PATCH 192/201] drm/i915/dp_mst: Add the MST topology state for modesetted CRTCs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 326b1e792ff08b4d8ecb9605aec98e4e5feef56e upstream. Add the MST topology for a CRTC to the atomic state if the driver needs to force a modeset on the CRTC after the encoder compute config functions are called. Later the MST encoder's disable hook also adds the state, but that isn't guaranteed to work (since in that hook getting the state may fail, which can't be handled there). This should fix that, while a later patch fixes the use of the MST state in the disable hook. v2: Add missing forward struct declartions, caught by hdrtest. v3: Factor out intel_dp_mst_add_topology_state_for_connector() used later in the patchset. Cc: Lyude Paul Cc: Ville Syrjälä Cc: stable@vger.kernel.org # 6.1 Reviewed-by: Ville Syrjälä # v2 Reviewed-by: Lyude Paul Acked-by: Lyude Paul Acked-by: Daniel Vetter Acked-by: Wayne Lin Acked-by: Jani Nikula Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20230206114856.2665066-1-imre.deak@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/display/intel_display.c | 4 ++ drivers/gpu/drm/i915/display/intel_dp_mst.c | 61 ++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_dp_mst.h | 4 ++ 3 files changed, 69 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index de77054195c6..4bbb84847ecb 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -5969,6 +5969,10 @@ int intel_modeset_all_pipes(struct intel_atomic_state *state) if (ret) return ret; + ret = intel_dp_mst_add_topology_state_for_crtc(state, crtc); + if (ret) + return ret; + ret = intel_atomic_add_affected_planes(state, crtc); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 03604a37931c..27c2098dd707 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -1003,3 +1003,64 @@ bool intel_dp_mst_is_slave_trans(const struct intel_crtc_state *crtc_state) return crtc_state->mst_master_transcoder != INVALID_TRANSCODER && crtc_state->mst_master_transcoder != crtc_state->cpu_transcoder; } + +/** + * intel_dp_mst_add_topology_state_for_connector - add MST topology state for a connector + * @state: atomic state + * @connector: connector to add the state for + * @crtc: the CRTC @connector is attached to + * + * Add the MST topology state for @connector to @state. + * + * Returns 0 on success, negative error code on failure. + */ +static int +intel_dp_mst_add_topology_state_for_connector(struct intel_atomic_state *state, + struct intel_connector *connector, + struct intel_crtc *crtc) +{ + struct drm_dp_mst_topology_state *mst_state; + + if (!connector->mst_port) + return 0; + + mst_state = drm_atomic_get_mst_topology_state(&state->base, + &connector->mst_port->mst_mgr); + if (IS_ERR(mst_state)) + return PTR_ERR(mst_state); + + mst_state->pending_crtc_mask |= drm_crtc_mask(&crtc->base); + + return 0; +} + +/** + * intel_dp_mst_add_topology_state_for_crtc - add MST topology state for a CRTC + * @state: atomic state + * @crtc: CRTC to add the state for + * + * Add the MST topology state for @crtc to @state. + * + * Returns 0 on success, negative error code on failure. + */ +int intel_dp_mst_add_topology_state_for_crtc(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + struct drm_connector *_connector; + struct drm_connector_state *conn_state; + int i; + + for_each_new_connector_in_state(&state->base, _connector, conn_state, i) { + struct intel_connector *connector = to_intel_connector(_connector); + int ret; + + if (conn_state->crtc != &crtc->base) + continue; + + ret = intel_dp_mst_add_topology_state_for_connector(state, connector, crtc); + if (ret) + return ret; + } + + return 0; +} diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.h b/drivers/gpu/drm/i915/display/intel_dp_mst.h index f7301de6cdfb..f1815bb72267 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.h +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.h @@ -8,6 +8,8 @@ #include +struct intel_atomic_state; +struct intel_crtc; struct intel_crtc_state; struct intel_digital_port; struct intel_dp; @@ -18,5 +20,7 @@ int intel_dp_mst_encoder_active_links(struct intel_digital_port *dig_port); bool intel_dp_mst_is_master_trans(const struct intel_crtc_state *crtc_state); bool intel_dp_mst_is_slave_trans(const struct intel_crtc_state *crtc_state); bool intel_dp_mst_source_support(struct intel_dp *intel_dp); +int intel_dp_mst_add_topology_state_for_crtc(struct intel_atomic_state *state, + struct intel_crtc *crtc); #endif /* __INTEL_DP_MST_H__ */ From 27b5871abd5cc068c549fd23062c82e257fc0b9c Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 8 Feb 2023 13:42:57 +0200 Subject: [PATCH 193/201] drm/i915: Fix system suspend without fbdev being initialized commit 8038510b1fe443ffbc0e356db5f47cbb8678a594 upstream. If fbdev is not initialized for some reason - in practice on platforms without display - suspending fbdev should be skipped during system suspend, fix this up. While at it add an assert that suspending fbdev only happens with the display present. This fixes the following: [ 91.227923] PM: suspend entry (s2idle) [ 91.254598] Filesystems sync: 0.025 seconds [ 91.270518] Freezing user space processes [ 91.272266] Freezing user space processes completed (elapsed 0.001 seconds) [ 91.272686] OOM killer disabled. [ 91.272872] Freezing remaining freezable tasks [ 91.274295] Freezing remaining freezable tasks completed (elapsed 0.001 seconds) [ 91.659622] BUG: kernel NULL pointer dereference, address: 00000000000001c8 [ 91.659981] #PF: supervisor write access in kernel mode [ 91.660252] #PF: error_code(0x0002) - not-present page [ 91.660511] PGD 0 P4D 0 [ 91.660647] Oops: 0002 [#1] PREEMPT SMP NOPTI [ 91.660875] CPU: 4 PID: 917 Comm: bash Not tainted 6.2.0-rc7+ #54 [ 91.661185] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS edk2-20221117gitfff6d81270b5-9.fc37 unknown [ 91.661680] RIP: 0010:mutex_lock+0x19/0x30 [ 91.661914] Code: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 0f 1f 44 00 00 53 48 89 fb e8 62 d3 ff ff 31 c0 65 48 8b 14 25 00 15 03 00 48 0f b1 13 75 06 5b c3 cc cc cc cc 48 89 df 5b eb b4 0f 1f 40 [ 91.662840] RSP: 0018:ffffa1e8011ffc08 EFLAGS: 00010246 [ 91.663087] RAX: 0000000000000000 RBX: 00000000000001c8 RCX: 0000000000000000 [ 91.663440] RDX: ffff8be455eb0000 RSI: 0000000000000001 RDI: 00000000000001c8 [ 91.663802] RBP: ffff8be459440000 R08: ffff8be459441f08 R09: ffffffff8e1432c0 [ 91.664167] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000001 [ 91.664532] R13: 00000000000001c8 R14: 0000000000000000 R15: ffff8be442f4fb20 [ 91.664905] FS: 00007f28ffc16740(0000) GS:ffff8be4bb900000(0000) knlGS:0000000000000000 [ 91.665334] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 91.665626] CR2: 00000000000001c8 CR3: 0000000114926006 CR4: 0000000000770ee0 [ 91.665988] PKRU: 55555554 [ 91.666131] Call Trace: [ 91.666265] [ 91.666381] intel_fbdev_set_suspend+0x97/0x1b0 [i915] [ 91.666738] i915_drm_suspend+0xb9/0x100 [i915] [ 91.667029] pci_pm_suspend+0x78/0x170 [ 91.667234] ? __pfx_pci_pm_suspend+0x10/0x10 [ 91.667461] dpm_run_callback+0x47/0x150 [ 91.667673] __device_suspend+0x10a/0x4e0 [ 91.667880] dpm_suspend+0x134/0x270 [ 91.668069] dpm_suspend_start+0x79/0x80 [ 91.668272] suspend_devices_and_enter+0x11b/0x890 [ 91.668526] pm_suspend.cold+0x270/0x2fc [ 91.668737] state_store+0x46/0x90 [ 91.668916] kernfs_fop_write_iter+0x11b/0x200 [ 91.669153] vfs_write+0x1e1/0x3a0 [ 91.669336] ksys_write+0x53/0xd0 [ 91.669510] do_syscall_64+0x58/0xc0 [ 91.669699] ? syscall_exit_to_user_mode_prepare+0x18e/0x1c0 [ 91.669980] ? syscall_exit_to_user_mode_prepare+0x18e/0x1c0 [ 91.670278] ? syscall_exit_to_user_mode+0x17/0x40 [ 91.670524] ? do_syscall_64+0x67/0xc0 [ 91.670717] ? __irq_exit_rcu+0x3d/0x140 [ 91.670931] entry_SYSCALL_64_after_hwframe+0x72/0xdc [ 91.671202] RIP: 0033:0x7f28ffd14284 v2: CC stable. (Jani) Fixes: f8cc091e0530 ("drm/i915/fbdev: suspend HPD before fbdev unregistration") References: https://gitlab.freedesktop.org/drm/intel/-/issues/8015 Reported-and-tested-by: iczero Cc: Andrzej Hajda Cc: iczero Cc: # v6.1+ Reviewed-by: Jani Nikula Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20230208114300.3123934-2-imre.deak@intel.com (cherry picked from commit 9542d708409a41449e99c9a464deb5e062c4bee2) Signed-off-by: Jani Nikula Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/display/intel_fbdev.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index 112aa0447a0d..9899b5dcd291 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -624,7 +624,13 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous struct intel_fbdev *ifbdev = dev_priv->display.fbdev.fbdev; struct fb_info *info; - if (!ifbdev || !ifbdev->vma) + if (!ifbdev) + return; + + if (drm_WARN_ON(&dev_priv->drm, !HAS_DISPLAY(dev_priv))) + return; + + if (!ifbdev->vma) goto set_suspend; info = ifbdev->helper.fbdev; From 4ca25c0b74ddec3a70e605ff5582cf76f0e1383a Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Thu, 5 Jan 2023 15:31:29 +0100 Subject: [PATCH 194/201] media: uvcvideo: Fix race condition with usb_kill_urb commit 619d9b710cf06f7a00a17120ca92333684ac45a8 upstream. usb_kill_urb warranties that all the handlers are finished when it returns, but does not protect against threads that might be handling asynchronously the urb. For UVC, the function uvc_ctrl_status_event_async() takes care of control changes asynchronously. If the code is executed in the following order: CPU 0 CPU 1 ===== ===== uvc_status_complete() uvc_status_stop() uvc_ctrl_status_event_work() uvc_status_start() -> FAIL Then uvc_status_start will keep failing and this error will be shown: <4>[ 5.540139] URB 0000000000000000 submitted while active drivers/usb/core/urb.c:378 usb_submit_urb+0x4c3/0x528 Let's improve the current situation, by not re-submiting the urb if we are stopping the status event. Also process the queued work (if any) during stop. CPU 0 CPU 1 ===== ===== uvc_status_complete() uvc_status_stop() uvc_status_start() uvc_ctrl_status_event_work() -> FAIL Hopefully, with the usb layer protection this should be enough to cover all the cases. Cc: stable@vger.kernel.org Fixes: e5225c820c05 ("media: uvcvideo: Send a control event when a Control Change interrupt arrives") Reviewed-by: Yunke Cao Signed-off-by: Ricardo Ribalda Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/uvc/uvc_ctrl.c | 5 ++++ drivers/media/usb/uvc/uvc_status.c | 37 ++++++++++++++++++++++++++++++ drivers/media/usb/uvc/uvcvideo.h | 1 + 3 files changed, 43 insertions(+) diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 44b0cfb8ee1c..067b43a1cb3e 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -6,6 +6,7 @@ * Laurent Pinchart (laurent.pinchart@ideasonboard.com) */ +#include #include #include #include @@ -1509,6 +1510,10 @@ static void uvc_ctrl_status_event_work(struct work_struct *work) uvc_ctrl_status_event(w->chain, w->ctrl, w->data); + /* The barrier is needed to synchronize with uvc_status_stop(). */ + if (smp_load_acquire(&dev->flush_status)) + return; + /* Resubmit the URB. */ w->urb->interval = dev->int_ep->desc.bInterval; ret = usb_submit_urb(w->urb, GFP_KERNEL); diff --git a/drivers/media/usb/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c index 7518ffce22ed..4a92c989cf33 100644 --- a/drivers/media/usb/uvc/uvc_status.c +++ b/drivers/media/usb/uvc/uvc_status.c @@ -6,6 +6,7 @@ * Laurent Pinchart (laurent.pinchart@ideasonboard.com) */ +#include #include #include #include @@ -309,5 +310,41 @@ int uvc_status_start(struct uvc_device *dev, gfp_t flags) void uvc_status_stop(struct uvc_device *dev) { + struct uvc_ctrl_work *w = &dev->async_ctrl; + + /* + * Prevent the asynchronous control handler from requeing the URB. The + * barrier is needed so the flush_status change is visible to other + * CPUs running the asynchronous handler before usb_kill_urb() is + * called below. + */ + smp_store_release(&dev->flush_status, true); + + /* + * Cancel any pending asynchronous work. If any status event was queued, + * process it synchronously. + */ + if (cancel_work_sync(&w->work)) + uvc_ctrl_status_event(w->chain, w->ctrl, w->data); + + /* Kill the urb. */ usb_kill_urb(dev->int_urb); + + /* + * The URB completion handler may have queued asynchronous work. This + * won't resubmit the URB as flush_status is set, but it needs to be + * cancelled before returning or it could then race with a future + * uvc_status_start() call. + */ + if (cancel_work_sync(&w->work)) + uvc_ctrl_status_event(w->chain, w->ctrl, w->data); + + /* + * From this point, there are no events on the queue and the status URB + * is dead. No events will be queued until uvc_status_start() is called. + * The barrier is needed to make sure that flush_status is visible to + * uvc_ctrl_status_event_work() when uvc_status_start() will be called + * again. + */ + smp_store_release(&dev->flush_status, false); } diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index b0937703c725..33e7475d4e64 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -558,6 +558,7 @@ struct uvc_device { /* Status Interrupt Endpoint */ struct usb_host_endpoint *int_ep; struct urb *int_urb; + bool flush_status; u8 *status; struct input_dev *input; char input_phys[64]; From 3453b1b0439baa53fb491528e8591050534695a5 Mon Sep 17 00:00:00 2001 From: Xinghui Li Date: Wed, 2 Nov 2022 16:25:03 +0800 Subject: [PATCH 195/201] io_uring: fix two assignments in if conditions commit df730ec21f7ba395b1b22e7f93a3a85b1d1b7882 upstream. Fixes two errors: "ERROR: do not use assignment in if condition 130: FILE: io_uring/net.c:130: + if (!(issue_flags & IO_URING_F_UNLOCKED) && ERROR: do not use assignment in if condition 599: FILE: io_uring/poll.c:599: + } else if (!(issue_flags & IO_URING_F_UNLOCKED) &&" reported by checkpatch.pl in net.c and poll.c . Signed-off-by: Xinghui Li Reported-by: kernel test robot Link: https://lore.kernel.org/r/20221102082503.32236-1-korantwork@gmail.com [axboe: style tweaks] Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- io_uring/net.c | 16 +++++++++------- io_uring/poll.c | 7 +++++-- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/io_uring/net.c b/io_uring/net.c index 55d822beaf08..4fdc2770bbe4 100644 --- a/io_uring/net.c +++ b/io_uring/net.c @@ -126,13 +126,15 @@ static struct io_async_msghdr *io_msg_alloc_async(struct io_kiocb *req, struct io_cache_entry *entry; struct io_async_msghdr *hdr; - if (!(issue_flags & IO_URING_F_UNLOCKED) && - (entry = io_alloc_cache_get(&ctx->netmsg_cache)) != NULL) { - hdr = container_of(entry, struct io_async_msghdr, cache); - hdr->free_iov = NULL; - req->flags |= REQ_F_ASYNC_DATA; - req->async_data = hdr; - return hdr; + if (!(issue_flags & IO_URING_F_UNLOCKED)) { + entry = io_alloc_cache_get(&ctx->netmsg_cache); + if (entry) { + hdr = container_of(entry, struct io_async_msghdr, cache); + hdr->free_iov = NULL; + req->flags |= REQ_F_ASYNC_DATA; + req->async_data = hdr; + return hdr; + } } if (!io_alloc_async_data(req)) { diff --git a/io_uring/poll.c b/io_uring/poll.c index ab5ae475840f..8aa9dd9e504a 100644 --- a/io_uring/poll.c +++ b/io_uring/poll.c @@ -678,10 +678,13 @@ static struct async_poll *io_req_alloc_apoll(struct io_kiocb *req, if (req->flags & REQ_F_POLLED) { apoll = req->apoll; kfree(apoll->double_poll); - } else if (!(issue_flags & IO_URING_F_UNLOCKED) && - (entry = io_alloc_cache_get(&ctx->apoll_cache)) != NULL) { + } else if (!(issue_flags & IO_URING_F_UNLOCKED)) { + entry = io_alloc_cache_get(&ctx->apoll_cache); + if (entry == NULL) + goto alloc_apoll; apoll = container_of(entry, struct async_poll, cache); } else { +alloc_apoll: apoll = kmalloc(sizeof(*apoll), GFP_ATOMIC); if (unlikely(!apoll)) return NULL; From c6b9c79c3df9200b71c19e525c89dce8764d0fc1 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Sat, 25 Feb 2023 12:53:53 -0700 Subject: [PATCH 196/201] io_uring/poll: allow some retries for poll triggering spuriously commit c16bda37594f83147b167d381d54c010024efecf upstream. If we get woken spuriously when polling and fail the operation with -EAGAIN again, then we generally only allow polling again if data had been transferred at some point. This is indicated with REQ_F_PARTIAL_IO. However, if the spurious poll triggers when the socket was originally empty, then we haven't transferred data yet and we will fail the poll re-arm. This either punts the socket to io-wq if it's blocking, or it fails the request with -EAGAIN if not. Neither condition is desirable, as the former will slow things down, while the latter will make the application confused. We want to ensure that a repeated poll trigger doesn't lead to infinite work making no progress, that's what the REQ_F_PARTIAL_IO check was for. But it doesn't protect against a loop post the first receive, and it's unnecessarily strict if we started out with an empty socket. Add a somewhat random retry count, just to put an upper limit on the potential number of retries that will be done. This should be high enough that we won't really hit it in practice, unless something needs to be aborted anyway. Cc: stable@vger.kernel.org # v5.10+ Link: https://github.com/axboe/liburing/issues/364 Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- io_uring/poll.c | 14 ++++++++++++-- io_uring/poll.h | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/io_uring/poll.c b/io_uring/poll.c index 8aa9dd9e504a..56dbd1863c78 100644 --- a/io_uring/poll.c +++ b/io_uring/poll.c @@ -668,6 +668,14 @@ static void io_async_queue_proc(struct file *file, struct wait_queue_head *head, __io_queue_proc(&apoll->poll, pt, head, &apoll->double_poll); } +/* + * We can't reliably detect loops in repeated poll triggers and issue + * subsequently failing. But rather than fail these immediately, allow a + * certain amount of retries before we give up. Given that this condition + * should _rarely_ trigger even once, we should be fine with a larger value. + */ +#define APOLL_MAX_RETRY 128 + static struct async_poll *io_req_alloc_apoll(struct io_kiocb *req, unsigned issue_flags) { @@ -683,14 +691,18 @@ static struct async_poll *io_req_alloc_apoll(struct io_kiocb *req, if (entry == NULL) goto alloc_apoll; apoll = container_of(entry, struct async_poll, cache); + apoll->poll.retries = APOLL_MAX_RETRY; } else { alloc_apoll: apoll = kmalloc(sizeof(*apoll), GFP_ATOMIC); if (unlikely(!apoll)) return NULL; + apoll->poll.retries = APOLL_MAX_RETRY; } apoll->double_poll = NULL; req->apoll = apoll; + if (unlikely(!--apoll->poll.retries)) + return NULL; return apoll; } @@ -712,8 +724,6 @@ int io_arm_poll_handler(struct io_kiocb *req, unsigned issue_flags) return IO_APOLL_ABORTED; if (!file_can_poll(req->file)) return IO_APOLL_ABORTED; - if ((req->flags & (REQ_F_POLLED|REQ_F_PARTIAL_IO)) == REQ_F_POLLED) - return IO_APOLL_ABORTED; if (!(req->flags & REQ_F_APOLL_MULTISHOT)) mask |= EPOLLONESHOT; diff --git a/io_uring/poll.h b/io_uring/poll.h index 5f3bae50fc81..b2393b403a2c 100644 --- a/io_uring/poll.h +++ b/io_uring/poll.h @@ -12,6 +12,7 @@ struct io_poll { struct file *file; struct wait_queue_head *head; __poll_t events; + int retries; struct wait_queue_entry wait; }; From 8b38969fa01662ec539a0d08a8ea5ec6f31fa4ed Mon Sep 17 00:00:00 2001 From: Pierre Gondois Date: Wed, 15 Feb 2023 17:10:47 +0100 Subject: [PATCH 197/201] arm64: efi: Make efi_rt_lock a raw_spinlock commit 0e68b5517d3767562889f1d83fdb828c26adb24f upstream. Running a rt-kernel base on 6.2.0-rc3-rt1 on an Ampere Altra outputs the following: BUG: sleeping function called from invalid context at kernel/locking/spinlock_rt.c:46 in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 9, name: kworker/u320:0 preempt_count: 2, expected: 0 RCU nest depth: 0, expected: 0 3 locks held by kworker/u320:0/9: #0: ffff3fff8c27d128 ((wq_completion)efi_rts_wq){+.+.}-{0:0}, at: process_one_work (./include/linux/atomic/atomic-long.h:41) #1: ffff80000861bdd0 ((work_completion)(&efi_rts_work.work)){+.+.}-{0:0}, at: process_one_work (./include/linux/atomic/atomic-long.h:41) #2: ffffdf7e1ed3e460 (efi_rt_lock){+.+.}-{3:3}, at: efi_call_rts (drivers/firmware/efi/runtime-wrappers.c:101) Preemption disabled at: efi_virtmap_load (./arch/arm64/include/asm/mmu_context.h:248) CPU: 0 PID: 9 Comm: kworker/u320:0 Tainted: G W 6.2.0-rc3-rt1 Hardware name: WIWYNN Mt.Jade Server System B81.03001.0005/Mt.Jade Motherboard, BIOS 1.08.20220218 (SCP: 1.08.20220218) 2022/02/18 Workqueue: efi_rts_wq efi_call_rts Call trace: dump_backtrace (arch/arm64/kernel/stacktrace.c:158) show_stack (arch/arm64/kernel/stacktrace.c:165) dump_stack_lvl (lib/dump_stack.c:107 (discriminator 4)) dump_stack (lib/dump_stack.c:114) __might_resched (kernel/sched/core.c:10134) rt_spin_lock (kernel/locking/rtmutex.c:1769 (discriminator 4)) efi_call_rts (drivers/firmware/efi/runtime-wrappers.c:101) [...] This seems to come from commit ff7a167961d1 ("arm64: efi: Execute runtime services from a dedicated stack") which adds a spinlock. This spinlock is taken through: efi_call_rts() \-efi_call_virt() \-efi_call_virt_pointer() \-arch_efi_call_virt_setup() Make 'efi_rt_lock' a raw_spinlock to avoid being preempted. [ardb: The EFI runtime services are called with a different set of translation tables, and are permitted to use the SIMD registers. The context switch code preserves/restores neither, and so EFI calls must be made with preemption disabled, rather than only disabling migration.] Fixes: ff7a167961d1 ("arm64: efi: Execute runtime services from a dedicated stack") Signed-off-by: Pierre Gondois Cc: # v6.1+ Signed-off-by: Ard Biesheuvel Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/efi.h | 6 +++--- arch/arm64/kernel/efi.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index b13c22046de5..62c846be2d76 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -33,7 +33,7 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md); ({ \ efi_virtmap_load(); \ __efi_fpsimd_begin(); \ - spin_lock(&efi_rt_lock); \ + raw_spin_lock(&efi_rt_lock); \ }) #undef arch_efi_call_virt @@ -42,12 +42,12 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md); #define arch_efi_call_virt_teardown() \ ({ \ - spin_unlock(&efi_rt_lock); \ + raw_spin_unlock(&efi_rt_lock); \ __efi_fpsimd_end(); \ efi_virtmap_unload(); \ }) -extern spinlock_t efi_rt_lock; +extern raw_spinlock_t efi_rt_lock; extern u64 *efi_rt_stack_top; efi_status_t __efi_rt_asm_wrapper(void *, const char *, ...); diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index b273900f4566..a30dbe4b95cd 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c @@ -146,7 +146,7 @@ asmlinkage efi_status_t efi_handle_corrupted_x18(efi_status_t s, const char *f) return s; } -DEFINE_SPINLOCK(efi_rt_lock); +DEFINE_RAW_SPINLOCK(efi_rt_lock); asmlinkage u64 *efi_rt_stack_top __ro_after_init; From 96122e776fe7041c7d50cfd98140da4a0f4427c0 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Thu, 3 Nov 2022 18:10:35 -0700 Subject: [PATCH 198/201] arm64: mte: Fix/clarify the PG_mte_tagged semantics commit e059853d14ca4ed0f6a190d7109487918a22a976 upstream. Currently the PG_mte_tagged page flag mostly means the page contains valid tags and it should be set after the tags have been cleared or restored. However, in mte_sync_tags() it is set before setting the tags to avoid, in theory, a race with concurrent mprotect(PROT_MTE) for shared pages. However, a concurrent mprotect(PROT_MTE) with a copy on write in another thread can cause the new page to have stale tags. Similarly, tag reading via ptrace() can read stale tags if the PG_mte_tagged flag is set before actually clearing/restoring the tags. Fix the PG_mte_tagged semantics so that it is only set after the tags have been cleared or restored. This is safe for swap restoring into a MAP_SHARED or CoW page since the core code takes the page lock. Add two functions to test and set the PG_mte_tagged flag with acquire and release semantics. The downside is that concurrent mprotect(PROT_MTE) on a MAP_SHARED page may cause tag loss. This is already the case for KVM guests if a VMM changes the page protection while the guest triggers a user_mem_abort(). Signed-off-by: Catalin Marinas [pcc@google.com: fix build with CONFIG_ARM64_MTE disabled] Signed-off-by: Peter Collingbourne Reviewed-by: Cornelia Huck Reviewed-by: Steven Price Cc: Will Deacon Cc: Marc Zyngier Cc: Peter Collingbourne Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20221104011041.290951-3-pcc@google.com Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/mte.h | 30 ++++++++++++++++++++++++++++++ arch/arm64/include/asm/pgtable.h | 2 +- arch/arm64/kernel/cpufeature.c | 4 +++- arch/arm64/kernel/elfcore.c | 2 +- arch/arm64/kernel/hibernate.c | 2 +- arch/arm64/kernel/mte.c | 17 +++++++++++------ arch/arm64/kvm/guest.c | 4 ++-- arch/arm64/kvm/mmu.c | 4 ++-- arch/arm64/mm/copypage.c | 5 +++-- arch/arm64/mm/fault.c | 2 +- arch/arm64/mm/mteswap.c | 2 +- 11 files changed, 56 insertions(+), 18 deletions(-) diff --git a/arch/arm64/include/asm/mte.h b/arch/arm64/include/asm/mte.h index 760c62f8e22f..3f8199ba265a 100644 --- a/arch/arm64/include/asm/mte.h +++ b/arch/arm64/include/asm/mte.h @@ -37,6 +37,29 @@ void mte_free_tag_storage(char *storage); /* track which pages have valid allocation tags */ #define PG_mte_tagged PG_arch_2 +static inline void set_page_mte_tagged(struct page *page) +{ + /* + * Ensure that the tags written prior to this function are visible + * before the page flags update. + */ + smp_wmb(); + set_bit(PG_mte_tagged, &page->flags); +} + +static inline bool page_mte_tagged(struct page *page) +{ + bool ret = test_bit(PG_mte_tagged, &page->flags); + + /* + * If the page is tagged, ensure ordering with a likely subsequent + * read of the tags. + */ + if (ret) + smp_rmb(); + return ret; +} + void mte_zero_clear_page_tags(void *addr); void mte_sync_tags(pte_t old_pte, pte_t pte); void mte_copy_page_tags(void *kto, const void *kfrom); @@ -56,6 +79,13 @@ size_t mte_probe_user_range(const char __user *uaddr, size_t size); /* unused if !CONFIG_ARM64_MTE, silence the compiler */ #define PG_mte_tagged 0 +static inline void set_page_mte_tagged(struct page *page) +{ +} +static inline bool page_mte_tagged(struct page *page) +{ + return false; +} static inline void mte_zero_clear_page_tags(void *addr) { } diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index f1cfc44ef52f..5d0f1f7b7600 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -1050,7 +1050,7 @@ static inline void arch_swap_invalidate_area(int type) static inline void arch_swap_restore(swp_entry_t entry, struct folio *folio) { if (system_supports_mte() && mte_restore_tags(entry, &folio->page)) - set_bit(PG_mte_tagged, &folio->flags); + set_page_mte_tagged(&folio->page); } #endif /* CONFIG_ARM64_MTE */ diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 86b2f7ec6c67..b3eb53847c96 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -2074,8 +2074,10 @@ static void cpu_enable_mte(struct arm64_cpu_capabilities const *cap) * Clear the tags in the zero page. This needs to be done via the * linear map which has the Tagged attribute. */ - if (!test_and_set_bit(PG_mte_tagged, &ZERO_PAGE(0)->flags)) + if (!page_mte_tagged(ZERO_PAGE(0))) { mte_clear_page_tags(lm_alias(empty_zero_page)); + set_page_mte_tagged(ZERO_PAGE(0)); + } kasan_init_hw_tags_cpu(); } diff --git a/arch/arm64/kernel/elfcore.c b/arch/arm64/kernel/elfcore.c index 662a61e5e75e..2e94d20c4ac7 100644 --- a/arch/arm64/kernel/elfcore.c +++ b/arch/arm64/kernel/elfcore.c @@ -46,7 +46,7 @@ static int mte_dump_tag_range(struct coredump_params *cprm, * Pages mapped in user space as !pte_access_permitted() (e.g. * PROT_EXEC only) may not have the PG_mte_tagged flag set. */ - if (!test_bit(PG_mte_tagged, &page->flags)) { + if (!page_mte_tagged(page)) { put_page(page); dump_skip(cprm, MTE_PAGE_TAG_STORAGE); continue; diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c index af5df48ba915..788597a6b6a2 100644 --- a/arch/arm64/kernel/hibernate.c +++ b/arch/arm64/kernel/hibernate.c @@ -271,7 +271,7 @@ static int swsusp_mte_save_tags(void) if (!page) continue; - if (!test_bit(PG_mte_tagged, &page->flags)) + if (!page_mte_tagged(page)) continue; ret = save_tags(page, pfn); diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c index 7467217c1eaf..84a085d536f8 100644 --- a/arch/arm64/kernel/mte.c +++ b/arch/arm64/kernel/mte.c @@ -41,8 +41,10 @@ static void mte_sync_page_tags(struct page *page, pte_t old_pte, if (check_swap && is_swap_pte(old_pte)) { swp_entry_t entry = pte_to_swp_entry(old_pte); - if (!non_swap_entry(entry) && mte_restore_tags(entry, page)) + if (!non_swap_entry(entry) && mte_restore_tags(entry, page)) { + set_page_mte_tagged(page); return; + } } if (!pte_is_tagged) @@ -52,8 +54,10 @@ static void mte_sync_page_tags(struct page *page, pte_t old_pte, * Test PG_mte_tagged again in case it was racing with another * set_pte_at(). */ - if (!test_and_set_bit(PG_mte_tagged, &page->flags)) + if (!page_mte_tagged(page)) { mte_clear_page_tags(page_address(page)); + set_page_mte_tagged(page); + } } void mte_sync_tags(pte_t old_pte, pte_t pte) @@ -69,9 +73,11 @@ void mte_sync_tags(pte_t old_pte, pte_t pte) /* if PG_mte_tagged is set, tags have already been initialised */ for (i = 0; i < nr_pages; i++, page++) { - if (!test_bit(PG_mte_tagged, &page->flags)) + if (!page_mte_tagged(page)) { mte_sync_page_tags(page, old_pte, check_swap, pte_is_tagged); + set_page_mte_tagged(page); + } } /* ensure the tags are visible before the PTE is set */ @@ -96,8 +102,7 @@ int memcmp_pages(struct page *page1, struct page *page2) * pages is tagged, set_pte_at() may zero or change the tags of the * other page via mte_sync_tags(). */ - if (test_bit(PG_mte_tagged, &page1->flags) || - test_bit(PG_mte_tagged, &page2->flags)) + if (page_mte_tagged(page1) || page_mte_tagged(page2)) return addr1 != addr2; return ret; @@ -454,7 +459,7 @@ static int __access_remote_tags(struct mm_struct *mm, unsigned long addr, put_page(page); break; } - WARN_ON_ONCE(!test_bit(PG_mte_tagged, &page->flags)); + WARN_ON_ONCE(!page_mte_tagged(page)); /* limit access to the end of the page */ offset = offset_in_page(addr); diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 2ff13a3f8479..817fdd1ab778 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -1059,7 +1059,7 @@ long kvm_vm_ioctl_mte_copy_tags(struct kvm *kvm, maddr = page_address(page); if (!write) { - if (test_bit(PG_mte_tagged, &page->flags)) + if (page_mte_tagged(page)) num_tags = mte_copy_tags_to_user(tags, maddr, MTE_GRANULES_PER_PAGE); else @@ -1076,7 +1076,7 @@ long kvm_vm_ioctl_mte_copy_tags(struct kvm *kvm, * completed fully */ if (num_tags == MTE_GRANULES_PER_PAGE) - set_bit(PG_mte_tagged, &page->flags); + set_page_mte_tagged(page); kvm_release_pfn_dirty(pfn); } diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 60ee3d9f01f8..2c3759f1f2c5 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1110,9 +1110,9 @@ static int sanitise_mte_tags(struct kvm *kvm, kvm_pfn_t pfn, return -EFAULT; for (i = 0; i < nr_pages; i++, page++) { - if (!test_bit(PG_mte_tagged, &page->flags)) { + if (!page_mte_tagged(page)) { mte_clear_page_tags(page_address(page)); - set_bit(PG_mte_tagged, &page->flags); + set_page_mte_tagged(page); } } diff --git a/arch/arm64/mm/copypage.c b/arch/arm64/mm/copypage.c index 24913271e898..731d8a35701e 100644 --- a/arch/arm64/mm/copypage.c +++ b/arch/arm64/mm/copypage.c @@ -21,9 +21,10 @@ void copy_highpage(struct page *to, struct page *from) copy_page(kto, kfrom); - if (system_supports_mte() && test_bit(PG_mte_tagged, &from->flags)) { - set_bit(PG_mte_tagged, &to->flags); + if (system_supports_mte() && page_mte_tagged(from)) { + page_kasan_tag_reset(to); mte_copy_page_tags(kto, kfrom); + set_page_mte_tagged(to); } } EXPORT_SYMBOL(copy_highpage); diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 3eb2825d08cf..4ee20280133e 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -944,5 +944,5 @@ struct page *alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma, void tag_clear_highpage(struct page *page) { mte_zero_clear_page_tags(page_address(page)); - set_bit(PG_mte_tagged, &page->flags); + set_page_mte_tagged(page); } diff --git a/arch/arm64/mm/mteswap.c b/arch/arm64/mm/mteswap.c index bed803d8e158..70f913205db9 100644 --- a/arch/arm64/mm/mteswap.c +++ b/arch/arm64/mm/mteswap.c @@ -24,7 +24,7 @@ int mte_save_tags(struct page *page) { void *tag_storage, *ret; - if (!test_bit(PG_mte_tagged, &page->flags)) + if (!page_mte_tagged(page)) return 0; tag_storage = mte_allocate_tag_storage(); From 58b656177d17b753e4959eba8a2600f687119a26 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Tue, 14 Feb 2023 21:09:11 -0800 Subject: [PATCH 199/201] arm64: Reset KASAN tag in copy_highpage with HW tags only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit e74a68468062d7ebd8ce17069e12ccc64cc6a58c upstream. During page migration, the copy_highpage function is used to copy the page data to the target page. If the source page is a userspace page with MTE tags, the KASAN tag of the target page must have the match-all tag in order to avoid tag check faults during subsequent accesses to the page by the kernel. However, the target page may have been allocated in a number of ways, some of which will use the KASAN allocator and will therefore end up setting the KASAN tag to a non-match-all tag. Therefore, update the target page's KASAN tag to match the source page. We ended up unintentionally fixing this issue as a result of a bad merge conflict resolution between commit e059853d14ca ("arm64: mte: Fix/clarify the PG_mte_tagged semantics") and commit 20794545c146 ("arm64: kasan: Revert "arm64: mte: reset the page tag in page->flags""), which preserved a tag reset for PG_mte_tagged pages which was considered to be unnecessary at the time. Because SW tags KASAN uses separate tag storage, update the code to only reset the tags when HW tags KASAN is enabled. Signed-off-by: Peter Collingbourne Link: https://linux-review.googlesource.com/id/If303d8a709438d3ff5af5fd85706505830f52e0c Reported-by: "Kuan-Ying Lee (李冠穎)" Cc: # 6.1 Fixes: 20794545c146 ("arm64: kasan: Revert "arm64: mte: reset the page tag in page->flags"") Reviewed-by: Andrey Konovalov Link: https://lore.kernel.org/r/20230215050911.1433132-1-pcc@google.com Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman --- arch/arm64/mm/copypage.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/mm/copypage.c b/arch/arm64/mm/copypage.c index 731d8a35701e..6dbc822332f2 100644 --- a/arch/arm64/mm/copypage.c +++ b/arch/arm64/mm/copypage.c @@ -22,7 +22,8 @@ void copy_highpage(struct page *to, struct page *from) copy_page(kto, kfrom); if (system_supports_mte() && page_mte_tagged(from)) { - page_kasan_tag_reset(to); + if (kasan_hw_tags_enabled()) + page_kasan_tag_reset(to); mte_copy_page_tags(kto, kfrom); set_page_mte_tagged(to); } From cc4b55a48f4aabbac8d84cfa7e5ed17b2b061bc7 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Mon, 13 Feb 2023 15:09:26 +0800 Subject: [PATCH 200/201] usb: gadget: uvc: fix missing mutex_unlock() if kstrtou8() fails commit 7ebb605d2283fb2647b4fa82030307ce00bee436 upstream. If kstrtou8() fails, the mutex_unlock() is missed, move kstrtou8() before mutex_lock() to fix it up. Fixes: 0525210c9840 ("usb: gadget: uvc: Allow definition of XUs in configfs") Fixes: b3c839bd8a07 ("usb: gadget: uvc: Make bSourceID read/write") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20230213070926.776447-1-yangyingliang@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/uvc_configfs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 832565730d22..015a7bbd9bbf 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -524,6 +524,10 @@ static ssize_t uvcg_default_output_b_source_id_store(struct config_item *item, int result; u8 num; + result = kstrtou8(page, 0, &num); + if (result) + return result; + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ opts_item = group->cg_item.ci_parent->ci_parent-> @@ -531,10 +535,6 @@ static ssize_t uvcg_default_output_b_source_id_store(struct config_item *item, opts = to_f_uvc_opts(opts_item); cd = &opts->uvc_output_terminal; - result = kstrtou8(page, 0, &num); - if (result) - return result; - mutex_lock(&opts->lock); cd->bSourceID = num; mutex_unlock(&opts->lock); From 1cc3fcf63192dfbf5ac13bc6134ae9120ebdcba6 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 11 Mar 2023 13:55:44 +0100 Subject: [PATCH 201/201] Linux 6.1.18 Link: https://lore.kernel.org/r/20230310133717.050159289@linuxfoundation.org Tested-by: Markus Reichelt Tested-by: Jon Hunter Tested-by: Salvatore Bonaccorso Tested-by: Shuah Khan Tested-by: Guenter Roeck Tested-by: Bagas Sanjaya Tested-by: Linux Kernel Functional Testing Tested-by: Conor Dooley Tested-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index db482a420dca..a825361f7162 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 6 PATCHLEVEL = 1 -SUBLEVEL = 17 +SUBLEVEL = 18 EXTRAVERSION = NAME = Hurr durr I'ma ninja sloth