0001
0002
0003
0004
0005
0006
0007 #include <linux/kernel.h>
0008 #include <linux/module.h>
0009 #include <linux/slab.h>
0010 #include <net/sock.h>
0011 #include <linux/workqueue.h>
0012 #include <linux/connector.h>
0013 #include <linux/device-mapper.h>
0014 #include <linux/dm-log-userspace.h>
0015
0016 #include "dm-log-userspace-transfer.h"
0017
0018 static uint32_t dm_ulog_seq;
0019
0020
0021
0022
0023
0024
0025
0026 #define DM_ULOG_RETRY_TIMEOUT (15 * HZ)
0027
0028
0029
0030
0031 #define DM_ULOG_PREALLOCED_SIZE 512
0032 static struct cn_msg *prealloced_cn_msg;
0033 static struct dm_ulog_request *prealloced_ulog_tfr;
0034
0035 static struct cb_id ulog_cn_id = {
0036 .idx = CN_IDX_DM,
0037 .val = CN_VAL_DM_USERSPACE_LOG
0038 };
0039
0040 static DEFINE_MUTEX(dm_ulog_lock);
0041
0042 struct receiving_pkg {
0043 struct list_head list;
0044 struct completion complete;
0045
0046 uint32_t seq;
0047
0048 int error;
0049 size_t *data_size;
0050 char *data;
0051 };
0052
0053 static DEFINE_SPINLOCK(receiving_list_lock);
0054 static struct list_head receiving_list;
0055
0056 static int dm_ulog_sendto_server(struct dm_ulog_request *tfr)
0057 {
0058 int r;
0059 struct cn_msg *msg = prealloced_cn_msg;
0060
0061 memset(msg, 0, sizeof(struct cn_msg));
0062
0063 msg->id.idx = ulog_cn_id.idx;
0064 msg->id.val = ulog_cn_id.val;
0065 msg->ack = 0;
0066 msg->seq = tfr->seq;
0067 msg->len = sizeof(struct dm_ulog_request) + tfr->data_size;
0068
0069 r = cn_netlink_send(msg, 0, 0, gfp_any());
0070
0071 return r;
0072 }
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082 static int fill_pkg(struct cn_msg *msg, struct dm_ulog_request *tfr)
0083 {
0084 uint32_t rtn_seq = (msg) ? msg->seq : (tfr) ? tfr->seq : 0;
0085 struct receiving_pkg *pkg;
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097 list_for_each_entry(pkg, &receiving_list, list) {
0098 if (rtn_seq != pkg->seq)
0099 continue;
0100
0101 if (msg) {
0102 pkg->error = -msg->ack;
0103
0104
0105
0106
0107
0108 if (pkg->error != -EAGAIN)
0109 *(pkg->data_size) = 0;
0110 } else if (tfr->data_size > *(pkg->data_size)) {
0111 DMERR("Insufficient space to receive package [%u] "
0112 "(%u vs %zu)", tfr->request_type,
0113 tfr->data_size, *(pkg->data_size));
0114
0115 *(pkg->data_size) = 0;
0116 pkg->error = -ENOSPC;
0117 } else {
0118 pkg->error = tfr->error;
0119 memcpy(pkg->data, tfr->data, tfr->data_size);
0120 *(pkg->data_size) = tfr->data_size;
0121 }
0122 complete(&pkg->complete);
0123 return 0;
0124 }
0125
0126 return -ENOENT;
0127 }
0128
0129
0130
0131
0132
0133 static void cn_ulog_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
0134 {
0135 struct dm_ulog_request *tfr = (struct dm_ulog_request *)(msg + 1);
0136
0137 if (!capable(CAP_SYS_ADMIN))
0138 return;
0139
0140 spin_lock(&receiving_list_lock);
0141 if (msg->len == 0)
0142 fill_pkg(msg, NULL);
0143 else if (msg->len < sizeof(*tfr))
0144 DMERR("Incomplete message received (expected %u, got %u): [%u]",
0145 (unsigned)sizeof(*tfr), msg->len, msg->seq);
0146 else
0147 fill_pkg(NULL, tfr);
0148 spin_unlock(&receiving_list_lock);
0149 }
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170 int dm_consult_userspace(const char *uuid, uint64_t luid, int request_type,
0171 char *data, size_t data_size,
0172 char *rdata, size_t *rdata_size)
0173 {
0174 int r = 0;
0175 unsigned long tmo;
0176 size_t dummy = 0;
0177 int overhead_size = sizeof(struct dm_ulog_request) + sizeof(struct cn_msg);
0178 struct dm_ulog_request *tfr = prealloced_ulog_tfr;
0179 struct receiving_pkg pkg;
0180
0181
0182
0183
0184
0185
0186 if (data_size > (DM_ULOG_PREALLOCED_SIZE - overhead_size)) {
0187 DMINFO("Size of tfr exceeds preallocated size");
0188 return -EINVAL;
0189 }
0190
0191 if (!rdata_size)
0192 rdata_size = &dummy;
0193 resend:
0194
0195
0196
0197
0198 mutex_lock(&dm_ulog_lock);
0199
0200 memset(tfr, 0, DM_ULOG_PREALLOCED_SIZE - sizeof(struct cn_msg));
0201 memcpy(tfr->uuid, uuid, DM_UUID_LEN);
0202 tfr->version = DM_ULOG_REQUEST_VERSION;
0203 tfr->luid = luid;
0204 tfr->seq = dm_ulog_seq++;
0205
0206
0207
0208
0209
0210
0211 tfr->request_type = request_type & DM_ULOG_REQUEST_MASK;
0212
0213 tfr->data_size = data_size;
0214 if (data && data_size)
0215 memcpy(tfr->data, data, data_size);
0216
0217 memset(&pkg, 0, sizeof(pkg));
0218 init_completion(&pkg.complete);
0219 pkg.seq = tfr->seq;
0220 pkg.data_size = rdata_size;
0221 pkg.data = rdata;
0222 spin_lock(&receiving_list_lock);
0223 list_add(&(pkg.list), &receiving_list);
0224 spin_unlock(&receiving_list_lock);
0225
0226 r = dm_ulog_sendto_server(tfr);
0227
0228 mutex_unlock(&dm_ulog_lock);
0229
0230 if (r) {
0231 DMERR("Unable to send log request [%u] to userspace: %d",
0232 request_type, r);
0233 spin_lock(&receiving_list_lock);
0234 list_del_init(&(pkg.list));
0235 spin_unlock(&receiving_list_lock);
0236
0237 goto out;
0238 }
0239
0240 tmo = wait_for_completion_timeout(&(pkg.complete), DM_ULOG_RETRY_TIMEOUT);
0241 spin_lock(&receiving_list_lock);
0242 list_del_init(&(pkg.list));
0243 spin_unlock(&receiving_list_lock);
0244 if (!tmo) {
0245 DMWARN("[%s] Request timed out: [%u/%u] - retrying",
0246 (strlen(uuid) > 8) ?
0247 (uuid + (strlen(uuid) - 8)) : (uuid),
0248 request_type, pkg.seq);
0249 goto resend;
0250 }
0251
0252 r = pkg.error;
0253 if (r == -EAGAIN)
0254 goto resend;
0255
0256 out:
0257 return r;
0258 }
0259
0260 int dm_ulog_tfr_init(void)
0261 {
0262 int r;
0263 void *prealloced;
0264
0265 INIT_LIST_HEAD(&receiving_list);
0266
0267 prealloced = kmalloc(DM_ULOG_PREALLOCED_SIZE, GFP_KERNEL);
0268 if (!prealloced)
0269 return -ENOMEM;
0270
0271 prealloced_cn_msg = prealloced;
0272 prealloced_ulog_tfr = prealloced + sizeof(struct cn_msg);
0273
0274 r = cn_add_callback(&ulog_cn_id, "dmlogusr", cn_ulog_callback);
0275 if (r) {
0276 kfree(prealloced_cn_msg);
0277 return r;
0278 }
0279
0280 return 0;
0281 }
0282
0283 void dm_ulog_tfr_exit(void)
0284 {
0285 cn_del_callback(&ulog_cn_id);
0286 kfree(prealloced_cn_msg);
0287 }