diff options
author | Miloslav Trmač <mitr@redhat.com> | 2010-09-14 21:42:40 +0200 |
---|---|---|
committer | Miloslav Trmač <mitr@redhat.com> | 2010-09-14 21:42:40 +0200 |
commit | 582315bae470b30a78d6a624ac53e94c351f6b9b (patch) | |
tree | 65f89cee1f1aa4e44a4e6da03d529e8080e59f5f /cryptodev_main.c | |
parent | c788635e2fddab3cb38685a6affa85deaacd0b06 (diff) | |
download | cryptodev-linux-582315bae470b30a78d6a624ac53e94c351f6b9b.tar.gz cryptodev-linux-582315bae470b30a78d6a624ac53e94c351f6b9b.tar.xz cryptodev-linux-582315bae470b30a78d6a624ac53e94c351f6b9b.zip |
Add locking to struct alg_sock
Diffstat (limited to 'cryptodev_main.c')
-rw-r--r-- | cryptodev_main.c | 82 |
1 files changed, 53 insertions, 29 deletions
diff --git a/cryptodev_main.c b/cryptodev_main.c index 93bb676..73e2586 100644 --- a/cryptodev_main.c +++ b/cryptodev_main.c @@ -114,9 +114,11 @@ enum alg_op_type { struct alg_sock { struct sock sk; - /* enum alg_op_type; Only changes once, from OP_NONE */ + /* enum alg_op_type; Only changes once, from OP_NONE; alg_sock::mutex + protects the transition. */ atomic_t op_type; + struct mutex mutex; /* Protects everything below */ struct data_sock *slaves[1]; unsigned num_slaves, accept_idx; struct hash_data hash; @@ -322,8 +324,6 @@ static int do_data_sendmsg(struct kiocb *iocb, struct alg_sock *ask, char *buf; int res; - // FIXME: locking - DUMP_ASK(ask); switch (ask_op_type(ask)) { @@ -341,7 +341,9 @@ static int do_data_sendmsg(struct kiocb *iocb, struct alg_sock *ask, if (res != 0) goto err; + mutex_lock(&ask->mutex); res = _cryptodev_hash_update(&ask->hash, buf, total_len); + mutex_unlock(&ask->mutex); if (res < 0) goto err; @@ -372,8 +374,6 @@ static int do_data_recvmsg(struct kiocb *iocb, struct alg_sock *ask, unsigned index, struct msghdr *m, size_t total_len, int flags) { - // FIXME: locking - DUMP_ASK(ask); switch (ask_op_type(ask)) { @@ -388,7 +388,11 @@ static int do_data_recvmsg(struct kiocb *iocb, struct alg_sock *ask, return -EINVAL; BUG_ON(ask->hash.digestsize > sizeof(digest)); + mutex_lock(&ask->mutex); res = cryptodev_hash_final(&ask->hash, digest); + if (res >= 0) + res = cryptodev_hash_reset(&ask->hash); + mutex_unlock(&ask->mutex); if (res < 0) return res; @@ -396,10 +400,6 @@ static int do_data_recvmsg(struct kiocb *iocb, struct alg_sock *ask, if (res != 0) return res; - res = cryptodev_hash_reset(&ask->hash); - if (res != 0) - return res; - return ask->hash.digestsize; } @@ -459,6 +459,7 @@ static void alg_destruct(struct sock *sk) break; case OP_HASH: + /* Locking is not necessary, this is the only reference. */ cryptodev_hash_deinit(&ask->hash); break; @@ -469,6 +470,8 @@ static void alg_destruct(struct sock *sk) local_bh_disable(); sock_prot_inuse_add(sock_net(sk), &alg_proto, -1); local_bh_enable(); + + mutex_destroy(&ask->mutex); DUMP_ASK(ask); } @@ -489,6 +492,8 @@ static int alg_release(struct socket *sock) // skb_queue_purge(&sk->sk_write_queue);??? + /* Locking ask->mutex is not necessary here, ask->{slaves,num_slaves, + accept_idx} can only be manipulated through sock. */ for (i = 0; i < ask->num_slaves; i++) { struct data_sock *dsk; @@ -526,22 +531,28 @@ static int alg_bind(struct socket *sock, struct sockaddr *myaddr, ask = alg_sk(sock->sk); DUMP_ASK(ask); - // FIXME: locking - - if (ask_op_type(ask) != OP_NONE) - return -EINVAL; + mutex_lock(&ask->mutex); + if (ask_op_type(ask) != OP_NONE) { + res = -EINVAL; + goto out_unlock; + } if (strncmp(addr->salg_type, "hash", sizeof(addr->salg_type)) == 0) { BUG_ON(ask->hash.init != 0); res = cryptodev_hash_init(&ask->hash, addr->salg_tfm, NULL, 0); if (res != 0) - return res; + goto out_unlock; atomic_set(&ask->op_type, OP_HASH); - } else - return -EINVAL; + } else { + res = -EINVAL; + goto out_unlock; + } + res = 0; +out_unlock: + mutex_unlock(&ask->mutex); DUMP_ASK(ask); - return 0; + return res; } static int alg_accept(struct socket *sock, struct socket *newsock, int flags) @@ -549,14 +560,18 @@ static int alg_accept(struct socket *sock, struct socket *newsock, int flags) struct alg_sock *ask; struct data_sock *dsk; - // FIXME: locking ask = alg_sk(sock->sk); DUMP_ASK(ask); - if (ask->accept_idx >= ask->num_slaves) - return -EINVAL; + mutex_lock(&ask->mutex); + if (ask->accept_idx >= ask->num_slaves) { + mutex_unlock(&ask->mutex); + return -EINVAL; + } dsk = ask->slaves[ask->accept_idx]; ask->accept_idx++; + mutex_unlock(&ask->mutex); + DUMP_DSK(dsk); DUMP_ASK(ask); @@ -579,14 +594,11 @@ static int alg_listen(struct socket *sock, int len) struct alg_sock *ask; struct data_sock *dsk; size_t i; + int res; - // FIXME: locking ask = alg_sk(sock->sk); DUMP_ASK(ask); - if (ask->num_slaves != 0) - return -EINVAL; - switch (ask_op_type(ask)) { case OP_NONE: return -EDESTADDRREQ; @@ -599,9 +611,15 @@ static int alg_listen(struct socket *sock, int len) default: BUG(); } - BUG_ON(len > ARRAY_SIZE(ask->slaves)); + mutex_lock(&ask->mutex); + + if (ask->num_slaves != 0) { + res = -EINVAL; + goto out_unlock; + } + net = sock_net(sock->sk); for (i = 0; i < len; i++) { struct sock *newsk; @@ -625,9 +643,12 @@ static int alg_listen(struct socket *sock, int len) } ask->num_slaves = len; - DUMP_ASK(ask); + res = 0; - return 0; +out_unlock: + mutex_unlock(&ask->mutex); + DUMP_ASK(ask); + return res; err_partial: while (i != 0) { @@ -641,8 +662,8 @@ err_partial: sock_put(&dsk->sk); DUMP_DSK(dsk); } - DUMP_ASK(ask); - return -ENOMEM; + res = -ENOMEM; + goto out_unlock; } static int alg_sendmsg(struct kiocb *iocb, struct socket *sock, @@ -702,6 +723,7 @@ static int alg_create(struct net *net, struct socket *sock, int protocol, int kern) { struct sock *sk; + struct alg_sock *ask; if (sock->type != SOCK_STREAM) return -ESOCKTNOSUPPORT; @@ -715,6 +737,8 @@ static int alg_create(struct net *net, struct socket *sock, int protocol, return -ENOMEM; sock_init_data(sock, sk); + ask = alg_sk(sk); + mutex_init(&ask->mutex); local_bh_disable(); sock_prot_inuse_add(net, &alg_proto, 1); |