From 43f62aa3ad64048d1b4eabc741ca900c17ab3eb5 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Thu, 4 Sep 2008 07:30:19 +0200 Subject: [PATCH] --- yaml --- r: 111485 b: refs/heads/master c: 09856c108956c99088ead9267ccbd1dab77f7043 h: refs/heads/master i: 111483: 00d2bf66f20fb6106181a08397531864f68488c2 v: v3 --- [refs] | 2 +- trunk/net/dccp/ccid.c | 39 +++++++++++++++++++++++++++++---------- trunk/net/dccp/ccid.h | 1 + trunk/net/dccp/feat.c | 5 +++++ 4 files changed, 36 insertions(+), 11 deletions(-) diff --git a/[refs] b/[refs] index 3fabd12fd4fc..5ab08da4866d 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 5d3dac267a7fd0811ec777e76a81f97f5cdcb395 +refs/heads/master: 09856c108956c99088ead9267ccbd1dab77f7043 diff --git a/trunk/net/dccp/ccid.c b/trunk/net/dccp/ccid.c index 330372a1a0b6..e3fb52b4f5c6 100644 --- a/trunk/net/dccp/ccid.c +++ b/trunk/net/dccp/ccid.c @@ -196,22 +196,41 @@ int ccid_unregister(struct ccid_operations *ccid_ops) EXPORT_SYMBOL_GPL(ccid_unregister); +/** + * ccid_request_module - Pre-load CCID module for later use + * This should be called only from process context (e.g. during connection + * setup) and is necessary for later calls to ccid_new (typically in software + * interrupt), so that it has the modules available when they are needed. + */ +static int ccid_request_module(u8 id) +{ + if (!in_atomic()) { + ccids_read_lock(); + if (ccids[id] == NULL) { + ccids_read_unlock(); + return request_module("net-dccp-ccid-%d", id); + } + ccids_read_unlock(); + } + return 0; +} + +int ccid_request_modules(u8 const *ccid_array, u8 array_len) +{ +#ifdef CONFIG_KMOD + while (array_len--) + if (ccid_request_module(ccid_array[array_len])) + return -1; +#endif + return 0; +} + struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, gfp_t gfp) { struct ccid_operations *ccid_ops; struct ccid *ccid = NULL; ccids_read_lock(); -#ifdef CONFIG_KMOD - if (ccids[id] == NULL) { - /* We only try to load if in process context */ - ccids_read_unlock(); - if (gfp & GFP_ATOMIC) - goto out; - request_module("net-dccp-ccid-%d", id); - ccids_read_lock(); - } -#endif ccid_ops = ccids[id]; if (ccid_ops == NULL) goto out_unlock; diff --git a/trunk/net/dccp/ccid.h b/trunk/net/dccp/ccid.h index 18f69423a708..20ba066b2775 100644 --- a/trunk/net/dccp/ccid.h +++ b/trunk/net/dccp/ccid.h @@ -108,6 +108,7 @@ extern int ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len); extern int ccid_getsockopt_builtin_ccids(struct sock *sk, int len, char __user *, int __user *); +extern int ccid_request_modules(u8 const *ccid_array, u8 array_len); extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, gfp_t gfp); diff --git a/trunk/net/dccp/feat.c b/trunk/net/dccp/feat.c index a687740e4420..9a4938092783 100644 --- a/trunk/net/dccp/feat.c +++ b/trunk/net/dccp/feat.c @@ -1158,6 +1158,11 @@ int dccp_feat_init(struct sock *sk) ccid_get_builtin_ccids(&rx.val, &rx.len)) return -ENOBUFS; + /* Pre-load all CCID modules that are going to be advertised */ + rc = -EUNATCH; + if (ccid_request_modules(tx.val, tx.len)) + goto free_ccid_lists; + if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) || !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len)) goto free_ccid_lists;