diff options
author | Miloslav Trmač <mitr@redhat.com> | 2010-09-14 18:39:43 +0200 |
---|---|---|
committer | Miloslav Trmač <mitr@redhat.com> | 2010-09-14 18:39:43 +0200 |
commit | f91e641ee86217ff28a30057e7774fab3cc2b097 (patch) | |
tree | 0a9eda61844f2b609005a3fb5613c16b061f99b8 | |
parent | cba2b0cd7ba7368eb209be50d8be237cf7778eab (diff) | |
download | cryptodev-linux-f91e641ee86217ff28a30057e7774fab3cc2b097.tar.gz cryptodev-linux-f91e641ee86217ff28a30057e7774fab3cc2b097.tar.xz cryptodev-linux-f91e641ee86217ff28a30057e7774fab3cc2b097.zip |
Clean up data when last reference goes away
In particular, don't free hash context until both master and slave are
closed.
-rw-r--r-- | cryptodev_main.c | 58 |
1 files changed, 32 insertions, 26 deletions
diff --git a/cryptodev_main.c b/cryptodev_main.c index f90dd45..c52210d 100644 --- a/cryptodev_main.c +++ b/cryptodev_main.c @@ -97,7 +97,7 @@ int __get_userbuf(uint8_t __user * addr, uint32_t len, int write, /* A socket merely used for I/O. */ struct data_sock { struct sock sk; - struct alg_sock *master; /* See below for reference counting */ + struct alg_sock *master; /* NULL until master's accept() */ unsigned index; }; @@ -235,6 +235,15 @@ static struct proto alg_proto = { .name = "ALG", }; +/* We only call sock_put() from task context, so this is running in task + context as well. */ +static void data_destruct(struct sock *sk) +{ + local_bh_disable(); + sock_prot_inuse_add(sock_net(sk), &data_proto, -1); + local_bh_enable(); +} + static int data_release(struct socket *sock) { struct sock *sk; @@ -247,10 +256,6 @@ static int data_release(struct socket *sock) dsk = data_sk(sk); DUMP_DSK(dsk); - local_bh_disable(); - sock_prot_inuse_add(sock_net(sk), &data_proto, -1); - local_bh_enable(); - BUG_ON(dsk->master == NULL); sock_put(&dsk->master->sk); DUMP_DSK(dsk); @@ -271,7 +276,8 @@ static int do_data_sendmsg(struct kiocb *iocb, struct alg_sock *ask, BUG_ON(index != 0); BUG_ON(ask->hash.init == 0); - // FIXME: limit size, or use socket buffer + // FIXME: limit size, or use socket buffer, or refer to userspace + // pages directly buf = kmalloc(total_len, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -372,6 +378,22 @@ static const struct proto_ops data_proto_ops = { .splice_read = NULL, }; +/* We only call sock_put() from task context, so this is running in task + context as well. */ +static void alg_destruct(struct sock *sk) +{ + struct alg_sock *ask; + + ask = alg_sk(sk); + + if (ask->hash.init != 0) + cryptodev_hash_deinit(&ask->hash); + + local_bh_disable(); + sock_prot_inuse_add(sock_net(sk), &alg_proto, -1); + local_bh_enable(); +} + static int alg_release(struct socket *sock) { struct sock *sk; @@ -396,24 +418,10 @@ static int alg_release(struct socket *sock) BUG_ON(dsk == NULL); DUMP_DSK(dsk); - if (i >= ask->accept_idx) { // FIXME: cleaner - on last sock_put - local_bh_disable(); - sock_prot_inuse_add(sock_net(&dsk->sk), &data_proto, - -1); - local_bh_enable(); - } sock_put(&dsk->sk); DUMP_DSK(dsk); } - if (ask->hash.init != 0) - cryptodev_hash_deinit(&ask->hash); - - // FIXME: on last sock_put - local_bh_disable(); - sock_prot_inuse_add(sock_net(sk), &alg_proto, -1); - local_bh_enable(); - sock_put(sk); return 0; @@ -509,6 +517,8 @@ static int alg_listen(struct socket *sock, int len) sock_prot_inuse_add(net, &data_proto, 1); local_bh_enable(); + newsk->sk_destruct = data_destruct; + dsk = data_sk(newsk); dsk->index = i; DUMP_DSK(dsk); @@ -529,12 +539,6 @@ err_partial: BUG_ON(dsk == NULL); DUMP_DSK(dsk); - - // FIXME: cleaner - on last sock_put - local_bh_disable(); - sock_prot_inuse_add(sock_net(&dsk->sk), &data_proto, -1); - local_bh_enable(); - sock_put(&dsk->sk); DUMP_DSK(dsk); } @@ -617,6 +621,8 @@ static int alg_create(struct net *net, struct socket *sock, int protocol, sock_prot_inuse_add(net, &alg_proto, 1); local_bh_enable(); + sk->sk_destruct = alg_destruct; + return 0; } |