diff options
Diffstat (limited to 'ANDROID_3.4.5/drivers/md/dm-log-userspace-transfer.c')
-rw-r--r-- | ANDROID_3.4.5/drivers/md/dm-log-userspace-transfer.c | 286 |
1 files changed, 0 insertions, 286 deletions
diff --git a/ANDROID_3.4.5/drivers/md/dm-log-userspace-transfer.c b/ANDROID_3.4.5/drivers/md/dm-log-userspace-transfer.c deleted file mode 100644 index 08d9a207..00000000 --- a/ANDROID_3.4.5/drivers/md/dm-log-userspace-transfer.c +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright (C) 2006-2009 Red Hat, Inc. - * - * This file is released under the LGPL. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <net/sock.h> -#include <linux/workqueue.h> -#include <linux/connector.h> -#include <linux/device-mapper.h> -#include <linux/dm-log-userspace.h> - -#include "dm-log-userspace-transfer.h" - -static uint32_t dm_ulog_seq; - -/* - * Netlink/Connector is an unreliable protocol. How long should - * we wait for a response before assuming it was lost and retrying? - * (If we do receive a response after this time, it will be discarded - * and the response to the resent request will be waited for. - */ -#define DM_ULOG_RETRY_TIMEOUT (15 * HZ) - -/* - * Pre-allocated space for speed - */ -#define DM_ULOG_PREALLOCED_SIZE 512 -static struct cn_msg *prealloced_cn_msg; -static struct dm_ulog_request *prealloced_ulog_tfr; - -static struct cb_id ulog_cn_id = { - .idx = CN_IDX_DM, - .val = CN_VAL_DM_USERSPACE_LOG -}; - -static DEFINE_MUTEX(dm_ulog_lock); - -struct receiving_pkg { - struct list_head list; - struct completion complete; - - uint32_t seq; - - int error; - size_t *data_size; - char *data; -}; - -static DEFINE_SPINLOCK(receiving_list_lock); -static struct list_head receiving_list; - -static int dm_ulog_sendto_server(struct dm_ulog_request *tfr) -{ - int r; - struct cn_msg *msg = prealloced_cn_msg; - - memset(msg, 0, sizeof(struct cn_msg)); - - msg->id.idx = ulog_cn_id.idx; - msg->id.val = ulog_cn_id.val; - msg->ack = 0; - msg->seq = tfr->seq; - msg->len = sizeof(struct dm_ulog_request) + tfr->data_size; - - r = cn_netlink_send(msg, 0, gfp_any()); - - return r; -} - -/* - * Parameters for this function can be either msg or tfr, but not - * both. This function fills in the reply for a waiting request. - * If just msg is given, then the reply is simply an ACK from userspace - * that the request was received. - * - * Returns: 0 on success, -ENOENT on failure - */ -static int fill_pkg(struct cn_msg *msg, struct dm_ulog_request *tfr) -{ - uint32_t rtn_seq = (msg) ? msg->seq : (tfr) ? tfr->seq : 0; - struct receiving_pkg *pkg; - - /* - * The 'receiving_pkg' entries in this list are statically - * allocated on the stack in 'dm_consult_userspace'. - * Each process that is waiting for a reply from the user - * space server will have an entry in this list. - * - * We are safe to do it this way because the stack space - * is unique to each process, but still addressable by - * other processes. - */ - list_for_each_entry(pkg, &receiving_list, list) { - if (rtn_seq != pkg->seq) - continue; - - if (msg) { - pkg->error = -msg->ack; - /* - * If we are trying again, we will need to know our - * storage capacity. Otherwise, along with the - * error code, we make explicit that we have no data. - */ - if (pkg->error != -EAGAIN) - *(pkg->data_size) = 0; - } else if (tfr->data_size > *(pkg->data_size)) { - DMERR("Insufficient space to receive package [%u] " - "(%u vs %zu)", tfr->request_type, - tfr->data_size, *(pkg->data_size)); - - *(pkg->data_size) = 0; - pkg->error = -ENOSPC; - } else { - pkg->error = tfr->error; - memcpy(pkg->data, tfr->data, tfr->data_size); - *(pkg->data_size) = tfr->data_size; - } - complete(&pkg->complete); - return 0; - } - - return -ENOENT; -} - -/* - * This is the connector callback that delivers data - * that was sent from userspace. - */ -static void cn_ulog_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) -{ - struct dm_ulog_request *tfr = (struct dm_ulog_request *)(msg + 1); - - if (!capable(CAP_SYS_ADMIN)) - return; - - spin_lock(&receiving_list_lock); - if (msg->len == 0) - fill_pkg(msg, NULL); - else if (msg->len < sizeof(*tfr)) - DMERR("Incomplete message received (expected %u, got %u): [%u]", - (unsigned)sizeof(*tfr), msg->len, msg->seq); - else - fill_pkg(NULL, tfr); - spin_unlock(&receiving_list_lock); -} - -/** - * dm_consult_userspace - * @uuid: log's universal unique identifier (must be DM_UUID_LEN in size) - * @luid: log's local unique identifier - * @request_type: found in include/linux/dm-log-userspace.h - * @data: data to tx to the server - * @data_size: size of data in bytes - * @rdata: place to put return data from server - * @rdata_size: value-result (amount of space given/amount of space used) - * - * rdata_size is undefined on failure. - * - * Memory used to communicate with userspace is zero'ed - * before populating to ensure that no unwanted bits leak - * from kernel space to user-space. All userspace log communications - * between kernel and user space go through this function. - * - * Returns: 0 on success, -EXXX on failure - **/ -int dm_consult_userspace(const char *uuid, uint64_t luid, int request_type, - char *data, size_t data_size, - char *rdata, size_t *rdata_size) -{ - int r = 0; - size_t dummy = 0; - int overhead_size = sizeof(struct dm_ulog_request) + sizeof(struct cn_msg); - struct dm_ulog_request *tfr = prealloced_ulog_tfr; - struct receiving_pkg pkg; - - /* - * Given the space needed to hold the 'struct cn_msg' and - * 'struct dm_ulog_request' - do we have enough payload - * space remaining? - */ - if (data_size > (DM_ULOG_PREALLOCED_SIZE - overhead_size)) { - DMINFO("Size of tfr exceeds preallocated size"); - return -EINVAL; - } - - if (!rdata_size) - rdata_size = &dummy; -resend: - /* - * We serialize the sending of requests so we can - * use the preallocated space. - */ - mutex_lock(&dm_ulog_lock); - - memset(tfr, 0, DM_ULOG_PREALLOCED_SIZE - sizeof(struct cn_msg)); - memcpy(tfr->uuid, uuid, DM_UUID_LEN); - tfr->version = DM_ULOG_REQUEST_VERSION; - tfr->luid = luid; - tfr->seq = dm_ulog_seq++; - - /* - * Must be valid request type (all other bits set to - * zero). This reserves other bits for possible future - * use. - */ - tfr->request_type = request_type & DM_ULOG_REQUEST_MASK; - - tfr->data_size = data_size; - if (data && data_size) - memcpy(tfr->data, data, data_size); - - memset(&pkg, 0, sizeof(pkg)); - init_completion(&pkg.complete); - pkg.seq = tfr->seq; - pkg.data_size = rdata_size; - pkg.data = rdata; - spin_lock(&receiving_list_lock); - list_add(&(pkg.list), &receiving_list); - spin_unlock(&receiving_list_lock); - - r = dm_ulog_sendto_server(tfr); - - mutex_unlock(&dm_ulog_lock); - - if (r) { - DMERR("Unable to send log request [%u] to userspace: %d", - request_type, r); - spin_lock(&receiving_list_lock); - list_del_init(&(pkg.list)); - spin_unlock(&receiving_list_lock); - - goto out; - } - - r = wait_for_completion_timeout(&(pkg.complete), DM_ULOG_RETRY_TIMEOUT); - spin_lock(&receiving_list_lock); - list_del_init(&(pkg.list)); - spin_unlock(&receiving_list_lock); - if (!r) { - DMWARN("[%s] Request timed out: [%u/%u] - retrying", - (strlen(uuid) > 8) ? - (uuid + (strlen(uuid) - 8)) : (uuid), - request_type, pkg.seq); - goto resend; - } - - r = pkg.error; - if (r == -EAGAIN) - goto resend; - -out: - return r; -} - -int dm_ulog_tfr_init(void) -{ - int r; - void *prealloced; - - INIT_LIST_HEAD(&receiving_list); - - prealloced = kmalloc(DM_ULOG_PREALLOCED_SIZE, GFP_KERNEL); - if (!prealloced) - return -ENOMEM; - - prealloced_cn_msg = prealloced; - prealloced_ulog_tfr = prealloced + sizeof(struct cn_msg); - - r = cn_add_callback(&ulog_cn_id, "dmlogusr", cn_ulog_callback); - if (r) { - cn_del_callback(&ulog_cn_id); - return r; - } - - return 0; -} - -void dm_ulog_tfr_exit(void) -{ - cn_del_callback(&ulog_cn_id); - kfree(prealloced_cn_msg); -} |