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;
 
 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);
 
 
            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;