Skip to contentSkip to conversation

Refactoring and significantly reducing code complexity

RFC/REFACT Wang Jinchao 3 participants 13 messages Sep 28, 2023 – Oct 26, 2023

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

This is a refactored version with the following main changes:

- The parallel workqueue no longer uses the WQ_UNBOUND attribute
- Removal of CPU-related logic, sysfs-related interfaces
- removal of structures like padata_cpumask, and deletion of parallel_data
- Using completion to maintain sequencing
- no longer using lists
- removing structures like padata_list and padata_serial_queue
- Removal of padata_do_serial()
- padata automatically ensures the calling sequence.

Testing was conducted using ltp's pcrypt_aead01, and the execution time comparison between the old and new versions is as follows:

Old Version:
real 0m27.451s
user 0m0.031s
sys 0m0.260s

New Version:
real 0m21.351s
user 0m0.023s
sys 0m0.260s

---
 crypto/pcrypt.c        |  34 +-
 include/linux/padata.h |  95 +----
 kernel/padata.c        | 815 ++---------------------------------------
 3 files changed, 43 insertions(+), 901 deletions(-)
crypto/pcrypt.c +10 -24
index 8c1d0ca41213..db9a36c35229 100644
@@ -70,8 +70,6 @@ static void pcrypt_aead_done(void *data, int err)
 	struct padata_priv *padata = pcrypt_request_padata(preq);
 
 	padata->info = err;
-
-	padata_do_serial(padata);
 }
 
 static void pcrypt_aead_enc(struct padata_priv *padata)
@@ -86,7 +84,6 @@ static void pcrypt_aead_enc(struct padata_priv *padata)
 		return;
 
 	padata->info = ret;
-	padata_do_serial(padata);
 }
 
 static int pcrypt_aead_encrypt(struct aead_request *req)
@@ -114,7 +111,7 @@ static int pcrypt_aead_encrypt(struct aead_request *req)
 			       req->cryptlen, req->iv);
 	aead_request_set_ad(creq, req->assoclen);
 
-	err = padata_do_parallel(ictx->psenc, padata, &ctx->cb_cpu);
+	err = padata_do_parallel(ictx->psenc, padata);
 	if (!err)
 		return -EINPROGRESS;
 
@@ -133,7 +130,6 @@ static void pcrypt_aead_dec(struct padata_priv *padata)
 		return;
 
 	padata->info = ret;
-	padata_do_serial(padata);
 }
 
 static int pcrypt_aead_decrypt(struct aead_request *req)
@@ -161,7 +157,7 @@ static int pcrypt_aead_decrypt(struct aead_request *req)
 			       req->cryptlen, req->iv);
 	aead_request_set_ad(creq, req->assoclen);
 
-	err = padata_do_parallel(ictx->psdec, padata, &ctx->cb_cpu);
+	err = padata_do_parallel(ictx->psdec, padata);
 	if (!err)
 		return -EINPROGRESS;
 
@@ -304,31 +300,18 @@ static int pcrypt_create(struct crypto_template *tmpl, struct rtattr **tb)
 	return -EINVAL;
 }
 
-static int pcrypt_sysfs_add(struct padata_instance *pinst, const char *name)
-{
-	int ret;
-
-	pinst->kobj.kset = pcrypt_kset;
-	ret = kobject_add(&pinst->kobj, NULL, "%s", name);
-	if (!ret)
-		kobject_uevent(&pinst->kobj, KOBJ_ADD);
-
-	return ret;
-}
-
 static int pcrypt_init_padata(struct padata_instance **pinst, const char *name)
 {
 	int ret = -ENOMEM;
+	pr_info("%s:%d %s\n", __FILE__, __LINE__, __func__);
 
 	*pinst = padata_alloc(name);
+	pr_info("%s:%d %s\n", __FILE__, __LINE__, __func__);
+	pr_info("%s:%d %s *pinst=%p\n", __FILE__, __LINE__, __func__, *pinst);
+
 	if (!*pinst)
 		return ret;
-
-	ret = pcrypt_sysfs_add(*pinst, name);
-	if (ret)
-		padata_free(*pinst);
-
-	return ret;
+	return 0;
 }
 
 static struct crypto_template pcrypt_tmpl = {
@@ -344,15 +327,18 @@ static int __init pcrypt_init(void)
 	pcrypt_kset = kset_create_and_add("pcrypt", NULL, kernel_kobj);
 	if (!pcrypt_kset)
 		goto err;
+	pr_info("%s:%d %s\n", __FILE__, __LINE__, __func__);
 
 	err = pcrypt_init_padata(&pencrypt, "pencrypt");
 	if (err)
 		goto err_unreg_kset;
 
+	pr_info("%s:%d %s\n", __FILE__, __LINE__, __func__);
 	err = pcrypt_init_padata(&pdecrypt, "pdecrypt");
 	if (err)
 		goto err_deinit_pencrypt;
 
+	pr_info("%s:%d %s\n", __FILE__, __LINE__, __func__);
 	return crypto_register_template(&pcrypt_tmpl);
 
 err_deinit_pencrypt:
include/linux/padata.h +7 -88

147 lines not on this page · raw message

kernel/padata.c +26 -789

942 lines not on this page · raw message

Signature · 1 line
2.40.0
maintainer
#1 lore raw
Quoted 9 lines · Wang Jinchao

This is a refactored version with the following main changes:

- The parallel workqueue no longer uses the WQ_UNBOUND attribute
- Removal of CPU-related logic, sysfs-related interfaces
- removal of structures like padata_cpumask, and deletion of parallel_data
- Using completion to maintain sequencing
- no longer using lists
- removing structures like padata_list and padata_serial_queue
- Removal of padata_do_serial()

This removes all the logic that is needed to ensure that the parallelized objects return in the same order as they were before the parallelization. This change makes padata unusable for networking.

#2 lore raw
Quoted 11 lines · Steffen Klassert
Quoted 9 lines · Wang Jinchao

This is a refactored version with the following main changes:

- The parallel workqueue no longer uses the WQ_UNBOUND attribute
- Removal of CPU-related logic, sysfs-related interfaces
- removal of structures like padata_cpumask, and deletion of parallel_data
- Using completion to maintain sequencing
- no longer using lists
- removing structures like padata_list and padata_serial_queue
- Removal of padata_do_serial()

Quoted 4 lines

This removes all the logic that is needed to ensure that the parallelized objects return in the same order as they were before the parallelization. This change makes padata unusable for networking.

The RFC use the following three to ensure serial timing sequence:

1. Use alloc_ordered_workqueue() to create a serial worker queue where serial() function runs. This ensures that serial() function executes as serial work was enqueued using queue_work().
2. Queue the serial work before enqueueing parallel work in padata_do_parallel(). This ensures the serial work follows the same order as the padata_do_parallel().
3. The serial work wait for completion of parallel_done, which will be complete()ed after the parallel() function within the parallel work.

This is just a design idea, because I am not familiar with IPsec, I haven't tested it in a real network environment yet.
Could you give me some clues on how to use pcrypt in an IPsec scenario?

maintainer
#3 lore raw
Quoted 19 lines · Wang Jinchao
Quoted 11 lines · Steffen Klassert
Quoted 9 lines · Wang Jinchao

This is a refactored version with the following main changes:

- The parallel workqueue no longer uses the WQ_UNBOUND attribute
- Removal of CPU-related logic, sysfs-related interfaces
- removal of structures like padata_cpumask, and deletion of parallel_data
- Using completion to maintain sequencing
- no longer using lists
- removing structures like padata_list and padata_serial_queue
- Removal of padata_do_serial()

Quoted 4 lines

This removes all the logic that is needed to ensure that the parallelized objects return in the same order as they were before the parallelization. This change makes padata unusable for networking.

The RFC use the following three to ensure serial timing sequence:

Quoted 7 lines

1. Use alloc_ordered_workqueue() to create a serial worker queue where serial() function runs. This ensures that serial() function executes as serial work was enqueued using queue_work().
2. Queue the serial work before enqueueing parallel work in padata_do_parallel(). This ensures the serial work follows the same order as the padata_do_parallel().
3. The serial work wait for completion of parallel_done, which will be complete()ed after the parallel() function within the parallel work.

I had a closer look to the padata codebase now. The logic to parallelize/serialize changed quite a bit since I wrote padata initially. I don't understand the new logic completely, so we need to rely on Daniels review for this.

Quoted 3 lines

This is just a design idea, because I am not familiar with IPsec, I haven't tested it in a real network environment yet.
Could you give me some clues on how to use pcrypt in an IPsec scenario?

pcrypt has performance gains if the cost of the crypto oreration is higher than the cost of moving the crypto request to another cpu. That was the case back in the days, but the situation changed since then. We now have hardware support for crypto, like aes-ni etc. So for hardware supported algorithms, pcrypt will not help much. But it is still interesting for crypto algorithms that are implemented in software only.

Here is how you can instantiate a pcrypted
algorithm:

----------------------------------------------------
You need to instantiate pcrypt before you can use it.

You need either crconf or the tcrypt module to instantiate pcrypt.

With crconf:

You can get crconf from https://sourceforge.net/projects/crconf/
After installing crconf do e.g.

crconf add driver "pcrypt(authenc(hmac(sha1-generic),cbc(aes-asm)))" type 3

With tcrypt:

modprobe tcrypt alg="pcrypt(authenc(hmac(sha1-generic),cbc(aes-asm)))" type=3

The modprobe will return with an error, don't worry about it, that's ok.

Once you've did one of the above, your /proc/crypto should show something like:

name : authenc(hmac(sha1),cbc(aes))
driver : pcrypt(authenc(hmac(sha1-generic),cbc(aes-asm)))
module : pcrypt
priority : 2100
refcnt : 1
selftest : passed
type : aead
async : yes
blocksize : 16
ivsize : 16
maxauthsize : 20
geniv : <built-in>

Now pcrypt is instantiated, e.g. all new IPsec states (that do hmac-sha1, cbc-aes) will use it.

maintainer
#4 lore raw
In reply to Wang Jinchao
Quoted 2 lines · Wang Jinchao

This is just a design idea, because I am not familiar with IPsec, I haven't tested it in a real network environment yet.

Out of curiosity, what's your use case for padata?

#5 lore raw
Quoted 5 lines · Daniel Jordan
Quoted 2 lines · Wang Jinchao

This is just a design idea, because I am not familiar with IPsec, I haven't tested it in a real network environment yet.

Out of curiosity, what's your use case for padata?

When I wrote the rfc_v1 on September 28th, I only used the "pcrypt_aead01" test case from LTP. Thank you for you and Steffen's responses. I now have more test cases, but I haven't tested them yet.

#6 lore raw
In reply to Steffen Klassert
Quoted 11 lines · Steffen Klassert
Quoted 9 lines · Wang Jinchao

This is a refactored version with the following main changes:

- The parallel workqueue no longer uses the WQ_UNBOUND attribute
- Removal of CPU-related logic, sysfs-related interfaces
- removal of structures like padata_cpumask, and deletion of parallel_data
- Using completion to maintain sequencing
- no longer using lists
- removing structures like padata_list and padata_serial_queue
- Removal of padata_do_serial()

Quoted 4 lines

This removes all the logic that is needed to ensure that the parallelized objects return in the same order as they were before the parallelization. This change makes padata unusable for networking.

Hello Steffen,
I have constructed a scenario where parallel() time cost
is forced to be reversed , and then ensured the order using serial(). The tests have passed on a 32-core machine.
Can you please explain if my refactored approach guarantees the serial ordering?

Here is the code:

padata_test.c
--------------

```c
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/padata.h>

struct request {
  struct padata_priv padata;
  int seq;
  struct completion done;
};

#define TEST_ARRAY_SIZE 200

#define PARALLEL_BASE_TIME 10

static int serial_cnt;
static int shuffled;
struct request requests[TEST_ARRAY_SIZE];
void parallel(struct padata_priv *padata) {
  struct request *req = container_of(padata, struct request, padata);

  // The smaller the req->seq number, the longer the delay time
  // creating a reverse order.
  mdelay((TEST_ARRAY_SIZE - req->seq) * PARALLEL_BASE_TIME);
  msleep((TEST_ARRAY_SIZE - req->seq) * PARALLEL_BASE_TIME);
}

void serial(struct padata_priv *padata) {
  struct request *req = container_of(padata, struct request, padata);
  if (req->seq != serial_cnt)
    shuffled = 1;
  serial_cnt++;
  complete(&req->done);
}

struct padata_instance *pinst;
struct padata_shell *ps;
static int __init padata_test_init(void) {
  serial_cnt = 0;
  shuffled = 0;
  pinst = padata_alloc("padata_test");
  if (!pinst)
    return -ENOMEM;

  ps = padata_alloc_shell(pinst);

  for (int i = 0; i < TEST_ARRAY_SIZE; i++) {
    requests[i].padata.parallel = parallel;
    requests[i].padata.serial = serial;
    requests[i].seq = i;
    init_completion(&requests[i].done);
  }

  for (int i = 0; i < TEST_ARRAY_SIZE; i++) {
    padata_do_parallel(ps, &requests[i].padata);
  }

  // only wait for the last one 
  // if they were not done serially
  // the serial_cnt will not be TEST_ARRAY_SIZE
  // there was a shuffering
  int last = TEST_ARRAY_SIZE - 1;
  wait_for_completion(&requests[last].done);
  if (serial_cnt != TEST_ARRAY_SIZE)
	shuffled = 1;
  
  printk(KERN_INFO "padata_test: shuffled %d serial_cnt %d\n", shuffled,
         serial_cnt);
  return 0;
}

static void __exit padata_test_exit(void) {
  padata_free_shell(ps);
  padata_free(pinst);
}

module_init(padata_test_init);
module_exit(padata_test_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("wangjinchao");
MODULE_DESCRIPTION("padata Test Module");
```

Makefile
---------

```makefile
obj-m += padata_test.o

all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
```

run.sh
--------

```bash
make
dmesg -C
insmod padata_test.ko
rmmod padata_test
dmesg|grep serial_cnt
```
maintainer
#7 lore raw
In reply to Wang Jinchao

Hi,

Quoted 30 lines · Wang Jinchao

This is a refactored version with the following main changes:

- The parallel workqueue no longer uses the WQ_UNBOUND attribute
- Removal of CPU-related logic, sysfs-related interfaces
- removal of structures like padata_cpumask, and deletion of parallel_data
- Using completion to maintain sequencing
- no longer using lists
- removing structures like padata_list and padata_serial_queue
- Removal of padata_do_serial()
- padata automatically ensures the calling sequence.

Testing was conducted using ltp's pcrypt_aead01, and the execution time comparison between the old and new versions is as follows:

Old Version:
real 0m27.451s
user 0m0.031s
sys 0m0.260s

New Version:
real 0m21.351s
user 0m0.023s
sys 0m0.260s

---
 crypto/pcrypt.c        |  34 +-
 include/linux/padata.h |  95 +----
 kernel/padata.c        | 815 ++---------------------------------------
 3 files changed, 43 insertions(+), 901 deletions(-)

...

crypto/pcrypt.c static int pcrypt_create(struct crypto_template *tmpl, struct rtattr **tb) · line 317

Quoted 12 lines
crypto/pcrypt.c +0 -11
-static int pcrypt_sysfs_add(struct padata_instance *pinst, const char *name)
-{
-	int ret;
-
-	pinst->kobj.kset = pcrypt_kset;
-	ret = kobject_add(&pinst->kobj, NULL, "%s", name);
-	if (!ret)
-		kobject_uevent(&pinst->kobj, KOBJ_ADD);
-
-	return ret;
-}

Users might rely on the existence of that sysfs files, so removing this might be dangerous.

kernel/padata.c static void padata_parallel_worker(struct work_struct *parallel_work) · line 360

Quoted 8 lines

static void padata_serial_worker(struct work_struct *serial_work) {

kernel/padata.c +0 -6
-	struct padata_serial_queue *squeue;
-	struct parallel_data *pd;
-	LIST_HEAD(local_list);
-	int cnt;
-
-	local_bh_disable();

Note that the networking RX path must run with BHs off. The call to padata_do_parallel might come with BHs off and the serialization callback should also called with BHs off.

Please make sure that the networking usecase continues to work with that refactorization.

Thanks!

maintainer
#8 lore raw
In reply to Wang Jinchao

Hello,

Quoted 1 line · Wang Jinchao

This is a refactored version with the following main changes:

The RFC overall is a nice simplification, and the basic approach of using an ordered workqueue seems to work.

Quoted 1 line

- The parallel workqueue no longer uses the WQ_UNBOUND attribute

What's the justification here? If it improves performance, please show numbers. Earlier tests[0] showed a large improvement when adding this flag.

[0] https://lore.kernel.org/linux-crypto/[email protected]/

Quoted 1 line

- Removal of CPU-related logic, sysfs-related interfaces

I agree with Steffen that we should continue to honor the cpumasks that the user sets.

The simplest way I see to make the parallel mask work with your refactor is to just make the parallel workqueue unbound again, since setting workqueue attributes is only allowed for unbound, and bring back some of the plumbing that leads to the apply_workqueue_attrs call.

The serial mask is trickier. Changing attributes of an ordered workqueue (the cpumask in this case) makes the kernel throw a warning...

static int apply_workqueue_attrs_locked

        ...
        /* creating multiple pwqs breaks ordering guarantee */                   
        if (!list_empty(&wq->pwqs)) {                                            
                if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))                  
                        return -EINVAL;                                          
                                                                                 
                wq->flags &= ~__WQ_ORDERED;                                      
        }

...but I'm not sure this is a fundamental limitation. The changelog of 0a94efb5acbb ("workqueue: implicit ordered attribute should be overridable") says changes to "max_active and some attribute changes" are rejected, but it might be possible to relax the warning to allow setting a cpumask while still rejecting other changes.

Quoted 8 lines

Testing was conducted using ltp's pcrypt_aead01, and the execution time comparison between the old and new versions is as follows:

Old Version:
real 0m27.451s
user 0m0.031s
sys 0m0.260s

Quoted 4 lines

New Version:
real 0m21.351s
user 0m0.023s
sys 0m0.260s

Great speedup. A test that runs many requests for a long time in parallel is also good to run, such as [0].

Quoted 1 line
(quoted diff) +0 -0
@@ -986,57 +281,27 @@ struct padata_instance *padata_alloc(const char *name)

...

kernel/padata.c struct padata_instance *padata_alloc(const char *name) · line 292

Quoted 3 lines
kernel/padata.c +3 -0
+	pinst->serial_wq = alloc_ordered_workqueue ("%s_serial",
+									WQ_MEM_RECLAIM | WQ_FREEZABLE,
+									name);

Why add these two WQ_ flags? Also, whitespace is kinda funky.

#9 lore raw
Quoted 8 lines · Daniel Jordan

Hello,

Quoted 1 line · Wang Jinchao

This is a refactored version with the following main changes:

The RFC overall is a nice simplification, and the basic approach of using an ordered workqueue seems to work.

Quoted 8 lines
Quoted 1 line

- The parallel workqueue no longer uses the WQ_UNBOUND attribute

What's the justification here? If it improves performance, please show numbers. Earlier tests[0] showed a large improvement when adding this flag.

[0] https://lore.kernel.org/linux-crypto/[email protected]/

When I wrote the email on September 28th, I only used the "pcrypt_aead01" test case from LTP. Thank you for you and Steffen's responses. I now have more test cases, but I haven't tested them yet.

Quoted 9 lines
Quoted 1 line

- Removal of CPU-related logic, sysfs-related interfaces

I agree with Steffen that we should continue to honor the cpumasks that the user sets.

The simplest way I see to make the parallel mask work with your refactor is to just make the parallel workqueue unbound again, since setting workqueue attributes is only allowed for unbound, and bring back some of the plumbing that leads to the apply_workqueue_attrs call.

You've convinced me, and I agree with your stance on keeping the cpumask. So, using WQ_UNBOUND is the right choice, and this will be reflected in my upcoming patches.

Quoted 14 lines

The serial mask is trickier. Changing attributes of an ordered workqueue (the cpumask in this case) makes the kernel throw a warning...

static int apply_workqueue_attrs_locked

        ...
        /* creating multiple pwqs breaks ordering guarantee */                   
        if (!list_empty(&wq->pwqs)) {                                            
                if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))                  
                        return -EINVAL;                                          
                                                                                 
                wq->flags &= ~__WQ_ORDERED;                                      
        }
Quoted 5 lines

...but I'm not sure this is a fundamental limitation. The changelog of 0a94efb5acbb ("workqueue: implicit ordered attribute should be overridable") says changes to "max_active and some attribute changes" are rejected, but it might be possible to relax the warning to allow setting a cpumask while still rejecting other changes.

Workqueue provides the alloc_ordered_workqueue method, which may be more suitable for serial workers.

Quoted 9 lines
Quoted 9 lines

Testing was conducted using ltp's pcrypt_aead01, and the execution time comparison between the old and new versions is as follows:

Old Version:
real 0m27.451s
user 0m0.031s
sys 0m0.260s

Quoted 8 lines
Quoted 4 lines

New Version:
real 0m21.351s
user 0m0.023s
sys 0m0.260s

Great speedup. A test that runs many requests for a long time in parallel is also good to run, such as [0].

I will conduct the test as previously mentioned.

Quoted 7 lines
Quoted 1 line
(quoted diff) +0 -0
@@ -986,57 +281,27 @@ struct padata_instance *padata_alloc(const char *name)

...

kernel/padata.c struct padata_instance *padata_alloc(const char *name) · line 292

Quoted 3 lines
kernel/padata.c +3 -0
+	pinst->serial_wq = alloc_ordered_workqueue ("%s_serial",
+									WQ_MEM_RECLAIM | WQ_FREEZABLE,
+									name);

Why add these two WQ_ flags? Also, whitespace is kinda funky.

You're right, I need to adjust this part of the code.

maintainer
#10 lore raw
In reply to Wang Jinchao
Quoted 17 lines · Wang Jinchao
include/linux/padata.h +0 -17
-/**
- * struct parallel_data - Internal control structure, covers everything
- * that depends on the cpumask in use.
- *
- * @ps: padata_shell object.
- * @reorder_list: percpu reorder lists
- * @squeue: percpu padata queues used for serialuzation.
- * @refcnt: Number of objects holding a reference on this parallel_data.
- * @seq_nr: Sequence number of the parallelized data object.
- * @processed: Number of already processed objects.
- * @cpu: Next CPU to be processed.
- * @cpumask: The cpumasks in use for parallel and serial workers.
- * @reorder_work: work struct for reordering.
- * @lock: Reorder lock.
- */
-struct parallel_data {
-	struct padata_shell		*ps;

include/linux/padata.h line 107

Quoted 10 lines
include/linux/padata.h +0 -10
-	struct padata_list		__percpu *reorder_list;
-	struct padata_serial_queue	__percpu *squeue;
-	refcount_t			refcnt;
-	unsigned int			seq_nr;
-	unsigned int			processed;
-	int				cpu;
-	struct padata_cpumask		cpumask;
-	struct work_struct		reorder_work;
-	spinlock_t                      ____cacheline_aligned lock;
-};

reorder_list used to serialize one sequence of objects per padata_shell, but now serial_wq serializes all sequences of objects in one list of work_structs. That works in theory, since a total order can maintain each sequence's order, but it's possible (not sure yet, need to think more) that this could lead to deadlocks or other issues in odd cases such as the one that padata_shell was introduced for in bbefa1dd6a6d ("crypto: pcrypt - Avoid deadlock by using per-instance padata queues").

The reproducer in that commit produces this splat when testing the RFC. Not sure if it's related to the above though.

[   40.084146] alg: aead: pcrypt(pcrypt(rfc4106-gcm-aesni)) encryption test failed (wrong result) on test vector 1, cfg="in-place (one sglist)"
[   40.087192] alg: self-tests for rfc4106(gcm(aes)) using pcrypt(pcrypt(rfc4106-gcm-aesni)) failed (rc=-22)
[   40.087195] ------------[ cut here ]------------
[   40.090296] alg: self-tests for rfc4106(gcm(aes)) using pcrypt(pcrypt(rfc4106-gcm-aesni)) failed (rc=-22)
[   40.090313] WARNING: CPU: 4 PID: 321 at crypto/testmgr.c:5936 alg_test+0x404/0x510
[   40.094020] Modules linked in: pcrypt
[   40.094882] CPU: 4 PID: 321 Comm: cryptomgr_test Not tainted 6.6.0-rc6-padata-refact-rfc-v1-test+ #3
[   40.096856] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Arch Linux 1.16.2-2-2 04/01/2014
[   40.098838] RIP: 0010:alg_test+0x404/0x510
[   40.099664] Code: e9 4a fd ff ff c6 44 24 17 01 41 bd ff ff ff ff e9 d1 fc ff ff 44 89 e9 48 89 da 4c 89 e6 48 c7 c7 a0 59 1d 82 e8 1c 45 c4 ff <0f> 0b e9 aa fe ff ff 0f 0b 48 c7 c7 80 58 1d 82 e8 e7 c6 cc ff e9
[   40.103180] RSP: 0018:ffffc90000343e10 EFLAGS: 00010286
[   40.104322] RAX: 0000000000000000 RBX: ffff88800421cc00 RCX: 0000000000000000
[   40.105875] RDX: 0000000000000002 RSI: ffffc90000343cc0 RDI: 00000000ffffffff
[   40.107467] RBP: 0000000000000883 R08: 00000000ffffdfff R09: 0000000000000001
[   40.109249] R10: 00000000ffffdfff R11: ffffffff824722a0 R12: ffff88800421cc80
[   40.110862] R13: 00000000ffffffea R14: 00000000ffffffff R15: 0000000000000000
[   40.112354] FS:  0000000000000000(0000) GS:ffff88807dd00000(0000) knlGS:0000000000000000
[   40.114132] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   40.115130] CR2: 00007f1808faba38 CR3: 000000000243e002 CR4: 0000000000170ea0
[   40.115959] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[   40.116630] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[   40.117261] Call Trace:
[   40.117559]  <TASK>
[   40.117811]  ? __warn+0x7d/0x140
[   40.118165]  ? alg_test+0x404/0x510
[   40.118452]  ? report_bug+0x18d/0x1c0
[   40.118743]  ? handle_bug+0x3a/0x70
[   40.118998]  ? exc_invalid_op+0x13/0x60
[   40.119265]  ? asm_exc_invalid_op+0x16/0x20
[   40.119597]  ? alg_test+0x404/0x510
[   40.119918]  ? _raw_spin_unlock_irqrestore+0x1b/0x40
[   40.120390]  ? try_to_wake_up+0x9a/0x6a0
[   40.120749]  ? preempt_count_add+0x6a/0xa0
[   40.121121]  ? __pfx_cryptomgr_test+0x10/0x10
[   40.121494]  cryptomgr_test+0x20/0x40
[   40.121751]  kthread+0x100/0x130
[   40.121979]  ? __pfx_kthread+0x10/0x10
[   40.122247]  ret_from_fork+0x30/0x50
[   40.122511]  ? __pfx_kthread+0x10/0x10
[   40.122775]  ret_from_fork_asm+0x1b/0x30
[   40.123050]  </TASK>
[   40.123207] ---[ end trace 0000000000000000 ]---
#11 lore raw
Quoted 29 lines · Daniel Jordan
Quoted 17 lines · Wang Jinchao
include/linux/padata.h +0 -17
-/**
- * struct parallel_data - Internal control structure, covers everything
- * that depends on the cpumask in use.
- *
- * @ps: padata_shell object.
- * @reorder_list: percpu reorder lists
- * @squeue: percpu padata queues used for serialuzation.
- * @refcnt: Number of objects holding a reference on this parallel_data.
- * @seq_nr: Sequence number of the parallelized data object.
- * @processed: Number of already processed objects.
- * @cpu: Next CPU to be processed.
- * @cpumask: The cpumasks in use for parallel and serial workers.
- * @reorder_work: work struct for reordering.
- * @lock: Reorder lock.
- */
-struct parallel_data {
-	struct padata_shell		*ps;

include/linux/padata.h line 107

Quoted 10 lines
include/linux/padata.h +0 -10
-	struct padata_list		__percpu *reorder_list;
-	struct padata_serial_queue	__percpu *squeue;
-	refcount_t			refcnt;
-	unsigned int			seq_nr;
-	unsigned int			processed;
-	int				cpu;
-	struct padata_cpumask		cpumask;
-	struct work_struct		reorder_work;
-	spinlock_t                      ____cacheline_aligned lock;
-};
Quoted 8 lines

reorder_list used to serialize one sequence of objects per padata_shell, but now serial_wq serializes all sequences of objects in one list of work_structs. That works in theory, since a total order can maintain each sequence's order, but it's possible (not sure yet, need to think more) that this could lead to deadlocks or other issues in odd cases such as the one that padata_shell was introduced for in bbefa1dd6a6d ("crypto: pcrypt - Avoid deadlock by using per-instance padata queues").

Yes, you are correct. This version is not only ordered at the padata_shell level but at the instance level, which indeed doesn't align with the design. Apart from potential deadlocks, it may also cause a padata_shell_B that should have completed earlier to be blocked by an unrelated padata_shell_B. I will address this issue in subsequent patches.

#12 lore raw
Quoted 38 lines · Wang Jinchao
Quoted 29 lines · Daniel Jordan
Quoted 17 lines · Wang Jinchao
include/linux/padata.h +0 -17
-/**
- * struct parallel_data - Internal control structure, covers everything
- * that depends on the cpumask in use.
- *
- * @ps: padata_shell object.
- * @reorder_list: percpu reorder lists
- * @squeue: percpu padata queues used for serialuzation.
- * @refcnt: Number of objects holding a reference on this parallel_data.
- * @seq_nr: Sequence number of the parallelized data object.
- * @processed: Number of already processed objects.
- * @cpu: Next CPU to be processed.
- * @cpumask: The cpumasks in use for parallel and serial workers.
- * @reorder_work: work struct for reordering.
- * @lock: Reorder lock.
- */
-struct parallel_data {
-	struct padata_shell		*ps;

include/linux/padata.h line 107

Quoted 10 lines
include/linux/padata.h +0 -10
-	struct padata_list		__percpu *reorder_list;
-	struct padata_serial_queue	__percpu *squeue;
-	refcount_t			refcnt;
-	unsigned int			seq_nr;
-	unsigned int			processed;
-	int				cpu;
-	struct padata_cpumask		cpumask;
-	struct work_struct		reorder_work;
-	spinlock_t                      ____cacheline_aligned lock;
-};
Quoted 8 lines

reorder_list used to serialize one sequence of objects per padata_shell, but now serial_wq serializes all sequences of objects in one list of work_structs. That works in theory, since a total order can maintain each sequence's order, but it's possible (not sure yet, need to think more) that this could lead to deadlocks or other issues in odd cases such as the one that padata_shell was introduced for in bbefa1dd6a6d ("crypto: pcrypt - Avoid deadlock by using per-instance padata queues").

Quoted 5 lines

Yes, you are correct. This version is not only ordered at the padata_shell level but at the instance level, which indeed doesn't align with the design. Apart from potential deadlocks, it may also cause a padata_shell_B that should have completed earlier to be blocked by an unrelated padata_shell_B. I will address this issue in subsequent patches.

Apart from potential deadlocks, it may also cause a padata_shell_B that should have completed earlier to be blocked by an unrelated padata_shell_A. I will address this issue in subsequent patches.