| /* | |
| * 2007+ Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru> | |
| * All rights reserved. | |
| * | |
| * This program is free software; you can redistribute it and/or modify | |
| * it under the terms of the GNU General Public License as published by | |
| * the Free Software Foundation; either version 2 of the License, or | |
| * (at your option) any later version. | |
| * | |
| * This program is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| * GNU General Public License for more details. | |
| */ | |
| #ifndef __DST_H | |
| #define __DST_H | |
| #include <linux/types.h> | |
| #include <linux/connector.h> | |
| #define DST_NAMELEN 32 | |
| #define DST_NAME "dst" | |
| enum { | |
| /* Remove node with given id from storage */ | |
| DST_DEL_NODE = 0, | |
| /* Add remote node with given id to the storage */ | |
| DST_ADD_REMOTE, | |
| /* Add local node with given id to the storage to be exported and used by remote peers */ | |
| DST_ADD_EXPORT, | |
| /* Crypto initialization command (hash/cipher used to protect the connection) */ | |
| DST_CRYPTO, | |
| /* Security attributes for given connection (permissions for example) */ | |
| DST_SECURITY, | |
| /* Register given node in the block layer subsystem */ | |
| DST_START, | |
| DST_CMD_MAX | |
| }; | |
| struct dst_ctl | |
| { | |
| /* Storage name */ | |
| char name[DST_NAMELEN]; | |
| /* Command flags */ | |
| __u32 flags; | |
| /* Command itself (see above) */ | |
| __u32 cmd; | |
| /* Maximum number of pages per single request in this device */ | |
| __u32 max_pages; | |
| /* Stale/error transaction scanning timeout in milliseconds */ | |
| __u32 trans_scan_timeout; | |
| /* Maximum number of retry sends before completing transaction as broken */ | |
| __u32 trans_max_retries; | |
| /* Storage size */ | |
| __u64 size; | |
| }; | |
| /* Reply command carries completion status */ | |
| struct dst_ctl_ack | |
| { | |
| struct cn_msg msg; | |
| int error; | |
| int unused[3]; | |
| }; | |
| /* | |
| * Unfortunaltely socket address structure is not exported to userspace | |
| * and is redefined there. | |
| */ | |
| #define SADDR_MAX_DATA 128 | |
| struct saddr { | |
| /* address family, AF_xxx */ | |
| unsigned short sa_family; | |
| /* 14 bytes of protocol address */ | |
| char sa_data[SADDR_MAX_DATA]; | |
| /* Number of bytes used in sa_data */ | |
| unsigned short sa_data_len; | |
| }; | |
| /* Address structure */ | |
| struct dst_network_ctl | |
| { | |
| /* Socket type: datagram, stream...*/ | |
| unsigned int type; | |
| /* Let me guess, is it a Jupiter diameter? */ | |
| unsigned int proto; | |
| /* Peer's address */ | |
| struct saddr addr; | |
| }; | |
| struct dst_crypto_ctl | |
| { | |
| /* Cipher and hash names */ | |
| char cipher_algo[DST_NAMELEN]; | |
| char hash_algo[DST_NAMELEN]; | |
| /* Key sizes. Can be zero for digest for example */ | |
| unsigned int cipher_keysize, hash_keysize; | |
| /* Alignment. Calculated by the DST itself. */ | |
| unsigned int crypto_attached_size; | |
| /* Number of threads to perform crypto operations */ | |
| int thread_num; | |
| }; | |
| /* Export security attributes have this bits checked in when client connects */ | |
| #define DST_PERM_READ (1<<0) | |
| #define DST_PERM_WRITE (1<<1) | |
| /* | |
| * Right now it is simple model, where each remote address | |
| * is assigned to set of permissions it is allowed to perform. | |
| * In real world block device does not know anything but | |
| * reading and writing, so it should be more than enough. | |
| */ | |
| struct dst_secure_user | |
| { | |
| unsigned int permissions; | |
| struct saddr addr; | |
| }; | |
| /* | |
| * Export control command: device to export and network address to accept | |
| * clients to work with given device | |
| */ | |
| struct dst_export_ctl | |
| { | |
| char device[DST_NAMELEN]; | |
| struct dst_network_ctl ctl; | |
| }; | |
| enum { | |
| DST_CFG = 1, /* Request remote configuration */ | |
| DST_IO, /* IO command */ | |
| DST_IO_RESPONSE, /* IO response */ | |
| DST_PING, /* Keepalive message */ | |
| DST_NCMD_MAX, | |
| }; | |
| struct dst_cmd | |
| { | |
| /* Network command itself, see above */ | |
| __u32 cmd; | |
| /* | |
| * Size of the attached data | |
| * (in most cases, for READ command it means how many bytes were requested) | |
| */ | |
| __u32 size; | |
| /* Crypto size: number of attached bytes with digest/hmac */ | |
| __u32 csize; | |
| /* Here we can carry secret data */ | |
| __u32 reserved; | |
| /* Read/write bits, see how they are encoded in bio structure */ | |
| __u64 rw; | |
| /* BIO flags */ | |
| __u64 flags; | |
| /* Unique command id (like transaction ID) */ | |
| __u64 id; | |
| /* Sector to start IO from */ | |
| __u64 sector; | |
| /* Hash data is placed after this header */ | |
| __u8 hash[0]; | |
| }; | |
| /* | |
| * Convert command to/from network byte order. | |
| * We do not use hton*() functions, since there is | |
| * no 64-bit implementation. | |
| */ | |
| static inline void dst_convert_cmd(struct dst_cmd *c) | |
| { | |
| c->cmd = __cpu_to_be32(c->cmd); | |
| c->csize = __cpu_to_be32(c->csize); | |
| c->size = __cpu_to_be32(c->size); | |
| c->sector = __cpu_to_be64(c->sector); | |
| c->id = __cpu_to_be64(c->id); | |
| c->flags = __cpu_to_be64(c->flags); | |
| c->rw = __cpu_to_be64(c->rw); | |
| } | |
| /* Transaction id */ | |
| typedef __u64 dst_gen_t; | |
| #ifdef __KERNEL__ | |
| #include <linux/blkdev.h> | |
| #include <linux/bio.h> | |
| #include <linux/device.h> | |
| #include <linux/mempool.h> | |
| #include <linux/net.h> | |
| #include <linux/poll.h> | |
| #include <linux/rbtree.h> | |
| #ifdef CONFIG_DST_DEBUG | |
| #define dprintk(f, a...) printk(KERN_NOTICE f, ##a) | |
| #else | |
| static inline void __attribute__ ((format (printf, 1, 2))) | |
| dprintk(const char *fmt, ...) {} | |
| #endif | |
| struct dst_node; | |
| struct dst_trans | |
| { | |
| /* DST node we are working with */ | |
| struct dst_node *n; | |
| /* Entry inside transaction tree */ | |
| struct rb_node trans_entry; | |
| /* Merlin kills this transaction when this memory cell equals zero */ | |
| atomic_t refcnt; | |
| /* How this transaction should be processed by crypto engine */ | |
| short enc; | |
| /* How many times this transaction was resent */ | |
| short retries; | |
| /* Completion status */ | |
| int error; | |
| /* When did we send it to the remote peer */ | |
| long send_time; | |
| /* My name is... | |
| * Well, computers does not speak, they have unique id instead */ | |
| dst_gen_t gen; | |
| /* Block IO we are working with */ | |
| struct bio *bio; | |
| /* Network command for above block IO request */ | |
| struct dst_cmd cmd; | |
| }; | |
| struct dst_crypto_engine | |
| { | |
| /* What should we do with all block requests */ | |
| struct crypto_hash *hash; | |
| struct crypto_ablkcipher *cipher; | |
| /* Pool of pages used to encrypt data into before sending */ | |
| int page_num; | |
| struct page **pages; | |
| /* What to do with current request */ | |
| int enc; | |
| /* Who we are and where do we go */ | |
| struct scatterlist *src, *dst; | |
| /* Maximum timeout waiting for encryption to be completed */ | |
| long timeout; | |
| /* IV is a 64-bit sequential counter */ | |
| u64 iv; | |
| /* Secret data */ | |
| void *private; | |
| /* Cached temporary data lives here */ | |
| int size; | |
| void *data; | |
| }; | |
| struct dst_state | |
| { | |
| /* The main state protection */ | |
| struct mutex state_lock; | |
| /* Polling machinery for sockets */ | |
| wait_queue_t wait; | |
| wait_queue_head_t *whead; | |
| /* Most of events are being waited here */ | |
| wait_queue_head_t thread_wait; | |
| /* Who owns this? */ | |
| struct dst_node *node; | |
| /* Network address for this state */ | |
| struct dst_network_ctl ctl; | |
| /* Permissions to work with: read-only or rw connection */ | |
| u32 permissions; | |
| /* Called when we need to clean private data */ | |
| void (* cleanup)(struct dst_state *st); | |
| /* Used by the server: BIO completion queues BIOs here */ | |
| struct list_head request_list; | |
| spinlock_t request_lock; | |
| /* Guess what? No, it is not number of planets */ | |
| atomic_t refcnt; | |
| /* This flags is set when connection should be dropped */ | |
| int need_exit; | |
| /* | |
| * Socket to work with. Second pointer is used for | |
| * lockless check if socket was changed before performing | |
| * next action (like working with cached polling result) | |
| */ | |
| struct socket *socket, *read_socket; | |
| /* Cached preallocated data */ | |
| void *data; | |
| unsigned int size; | |
| /* Currently processed command */ | |
| struct dst_cmd cmd; | |
| }; | |
| struct dst_info | |
| { | |
| /* Device size */ | |
| u64 size; | |
| /* Local device name for export devices */ | |
| char local[DST_NAMELEN]; | |
| /* Network setup */ | |
| struct dst_network_ctl net; | |
| /* Sysfs bits use this */ | |
| struct device device; | |
| }; | |
| struct dst_node | |
| { | |
| struct list_head node_entry; | |
| /* Hi, my name is stored here */ | |
| char name[DST_NAMELEN]; | |
| /* My cache name is stored here */ | |
| char cache_name[DST_NAMELEN]; | |
| /* Block device attached to given node. | |
| * Only valid for exporting nodes */ | |
| struct block_device *bdev; | |
| /* Network state machine for given peer */ | |
| struct dst_state *state; | |
| /* Block IO machinery */ | |
| struct request_queue *queue; | |
| struct gendisk *disk; | |
| /* Number of threads in processing pool */ | |
| int thread_num; | |
| /* Maximum number of pages in single IO */ | |
| int max_pages; | |
| /* I'm that big in bytes */ | |
| loff_t size; | |
| /* Exported to userspace node information */ | |
| struct dst_info *info; | |
| /* | |
| * Security attribute list. | |
| * Used only by exporting node currently. | |
| */ | |
| struct list_head security_list; | |
| struct mutex security_lock; | |
| /* | |
| * When this unerflows below zero, university collapses. | |
| * But this will not happen, since node will be freed, | |
| * when reference counter reaches zero. | |
| */ | |
| atomic_t refcnt; | |
| /* How precisely should I be started? */ | |
| int (*start)(struct dst_node *); | |
| /* Crypto capabilities */ | |
| struct dst_crypto_ctl crypto; | |
| u8 *hash_key; | |
| u8 *cipher_key; | |
| /* Pool of processing thread */ | |
| struct thread_pool *pool; | |
| /* Transaction IDs live here */ | |
| atomic_long_t gen; | |
| /* | |
| * How frequently and how many times transaction | |
| * tree should be scanned to drop stale objects. | |
| */ | |
| long trans_scan_timeout; | |
| int trans_max_retries; | |
| /* Small gnomes live here */ | |
| struct rb_root trans_root; | |
| struct mutex trans_lock; | |
| /* | |
| * Transaction cache/memory pool. | |
| * It is big enough to contain not only transaction | |
| * itself, but additional crypto data (digest/hmac). | |
| */ | |
| struct kmem_cache *trans_cache; | |
| mempool_t *trans_pool; | |
| /* This entity scans transaction tree */ | |
| struct delayed_work trans_work; | |
| wait_queue_head_t wait; | |
| }; | |
| /* Kernel representation of the security attribute */ | |
| struct dst_secure | |
| { | |
| struct list_head sec_entry; | |
| struct dst_secure_user sec; | |
| }; | |
| int dst_process_bio(struct dst_node *n, struct bio *bio); | |
| int dst_node_init_connected(struct dst_node *n, struct dst_network_ctl *r); | |
| int dst_node_init_listened(struct dst_node *n, struct dst_export_ctl *le); | |
| static inline struct dst_state *dst_state_get(struct dst_state *st) | |
| { | |
| BUG_ON(atomic_read(&st->refcnt) == 0); | |
| atomic_inc(&st->refcnt); | |
| return st; | |
| } | |
| void dst_state_put(struct dst_state *st); | |
| struct dst_state *dst_state_alloc(struct dst_node *n); | |
| int dst_state_socket_create(struct dst_state *st); | |
| void dst_state_socket_release(struct dst_state *st); | |
| void dst_state_exit_connected(struct dst_state *st); | |
| int dst_state_schedule_receiver(struct dst_state *st); | |
| void dst_dump_addr(struct socket *sk, struct sockaddr *sa, char *str); | |
| static inline void dst_state_lock(struct dst_state *st) | |
| { | |
| mutex_lock(&st->state_lock); | |
| } | |
| static inline void dst_state_unlock(struct dst_state *st) | |
| { | |
| mutex_unlock(&st->state_lock); | |
| } | |
| void dst_poll_exit(struct dst_state *st); | |
| int dst_poll_init(struct dst_state *st); | |
| static inline unsigned int dst_state_poll(struct dst_state *st) | |
| { | |
| unsigned int revents = POLLHUP | POLLERR; | |
| dst_state_lock(st); | |
| if (st->socket) | |
| revents = st->socket->ops->poll(NULL, st->socket, NULL); | |
| dst_state_unlock(st); | |
| return revents; | |
| } | |
| static inline int dst_thread_setup(void *private, void *data) | |
| { | |
| return 0; | |
| } | |
| void dst_node_put(struct dst_node *n); | |
| static inline struct dst_node *dst_node_get(struct dst_node *n) | |
| { | |
| atomic_inc(&n->refcnt); | |
| return n; | |
| } | |
| int dst_data_recv(struct dst_state *st, void *data, unsigned int size); | |
| int dst_recv_cdata(struct dst_state *st, void *cdata); | |
| int dst_data_send_header(struct socket *sock, | |
| void *data, unsigned int size, int more); | |
| int dst_send_bio(struct dst_state *st, struct dst_cmd *cmd, struct bio *bio); | |
| int dst_process_io(struct dst_state *st); | |
| int dst_export_crypto(struct dst_node *n, struct bio *bio); | |
| int dst_export_send_bio(struct bio *bio); | |
| int dst_start_export(struct dst_node *n); | |
| int __init dst_export_init(void); | |
| void dst_export_exit(void); | |
| /* Private structure for export block IO requests */ | |
| struct dst_export_priv | |
| { | |
| struct list_head request_entry; | |
| struct dst_state *state; | |
| struct bio *bio; | |
| struct dst_cmd cmd; | |
| }; | |
| static inline void dst_trans_get(struct dst_trans *t) | |
| { | |
| atomic_inc(&t->refcnt); | |
| } | |
| struct dst_trans *dst_trans_search(struct dst_node *node, dst_gen_t gen); | |
| int dst_trans_remove(struct dst_trans *t); | |
| int dst_trans_remove_nolock(struct dst_trans *t); | |
| void dst_trans_put(struct dst_trans *t); | |
| /* | |
| * Convert bio into network command. | |
| */ | |
| static inline void dst_bio_to_cmd(struct bio *bio, struct dst_cmd *cmd, | |
| u32 command, u64 id) | |
| { | |
| cmd->cmd = command; | |
| cmd->flags = (bio->bi_flags << BIO_POOL_BITS) >> BIO_POOL_BITS; | |
| cmd->rw = bio->bi_rw; | |
| cmd->size = bio->bi_size; | |
| cmd->csize = 0; | |
| cmd->id = id; | |
| cmd->sector = bio->bi_sector; | |
| }; | |
| int dst_trans_send(struct dst_trans *t); | |
| int dst_trans_crypto(struct dst_trans *t); | |
| int dst_node_crypto_init(struct dst_node *n, struct dst_crypto_ctl *ctl); | |
| void dst_node_crypto_exit(struct dst_node *n); | |
| static inline int dst_need_crypto(struct dst_node *n) | |
| { | |
| struct dst_crypto_ctl *c = &n->crypto; | |
| /* | |
| * Logical OR is appropriate here, but boolean one produces | |
| * more optimal code, so it is used instead. | |
| */ | |
| return (c->hash_algo[0] | c->cipher_algo[0]); | |
| } | |
| int dst_node_trans_init(struct dst_node *n, unsigned int size); | |
| void dst_node_trans_exit(struct dst_node *n); | |
| /* | |
| * Pool of threads. | |
| * Ready list contains threads currently free to be used, | |
| * active one contains threads with some work scheduled for them. | |
| * Caller can wait in given queue when thread is ready. | |
| */ | |
| struct thread_pool | |
| { | |
| int thread_num; | |
| struct mutex thread_lock; | |
| struct list_head ready_list, active_list; | |
| wait_queue_head_t wait; | |
| }; | |
| void thread_pool_del_worker(struct thread_pool *p); | |
| void thread_pool_del_worker_id(struct thread_pool *p, unsigned int id); | |
| int thread_pool_add_worker(struct thread_pool *p, | |
| char *name, | |
| unsigned int id, | |
| void *(* init)(void *data), | |
| void (* cleanup)(void *data), | |
| void *data); | |
| void thread_pool_destroy(struct thread_pool *p); | |
| struct thread_pool *thread_pool_create(int num, char *name, | |
| void *(* init)(void *data), | |
| void (* cleanup)(void *data), | |
| void *data); | |
| int thread_pool_schedule(struct thread_pool *p, | |
| int (* setup)(void *stored_private, void *setup_data), | |
| int (* action)(void *stored_private, void *setup_data), | |
| void *setup_data, long timeout); | |
| int thread_pool_schedule_private(struct thread_pool *p, | |
| int (* setup)(void *private, void *data), | |
| int (* action)(void *private, void *data), | |
| void *data, long timeout, void *id); | |
| #endif /* __KERNEL__ */ | |
| #endif /* __DST_H */ |