]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/blkmapd/device-process.c
blkmapd: Add complex block layout discovery and mapping daemon
[nfs-utils.git] / utils / blkmapd / device-process.c
1 /*
2  * device-process.c: detailed processing of device information sent
3  * from kernel.
4  *
5  * Copyright (c) 2006 The Regents of the University of Michigan.
6  * All rights reserved.
7  *
8  *  Andy Adamson <andros@citi.umich.edu>
9  *  Fred Isaman <iisaman@umich.edu>
10  *
11  * Copyright (c) 2010 EMC Corporation, Haiying Tang <Tang_Haiying@emc.com>
12  *
13  * Used codes in linux/fs/nfs/blocklayout/blocklayoutdev.c.
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions
17  * are met:
18  * 1. Redistributions of source code must retain the above copyright
19  *    notice, this list of conditions and the following disclaimer.
20  * 2. Redistributions in binary form must reproduce the above copyright
21  *    notice, this list of conditions and the following disclaimer in the
22  *    documentation and/or other materials provided with the distribution.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/user.h>
39 #include <arpa/inet.h>
40 #include <linux/kdev_t.h>
41
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <syslog.h>
47 #include <fcntl.h>
48 #include <errno.h>
49
50 #include "device-discovery.h"
51
52 static char *pretty_sig(char *sig, uint32_t siglen)
53 {
54         static char rs[100];
55         uint64_t sigval;
56         unsigned int i;
57
58         if (siglen <= sizeof(sigval)) {
59                 sigval = 0;
60                 for (i = 0; i < siglen; i++)
61                         sigval |= ((unsigned char *)sig)[i] << (i * 8);
62                 sprintf(rs, "0x%0llx", (unsigned long long) sigval);
63         } else {
64                 if (siglen > sizeof rs - 4) {
65                         siglen = sizeof rs - 4;
66                         sprintf(&rs[siglen], "...");
67                 } else
68                         rs[siglen] = '\0';
69                 memcpy(rs, sig, siglen);
70         }
71         return rs;
72 }
73
74 uint32_t *blk_overflow(uint32_t * p, uint32_t * end, size_t nbytes)
75 {
76         uint32_t *q = p + ((nbytes + 3) >> 2);
77
78         if (q > end || q < p)
79                 return NULL;
80         return p;
81 }
82
83 static int decode_blk_signature(uint32_t **pp, uint32_t * end,
84                                 struct bl_sig *sig)
85 {
86         int i;
87         uint32_t siglen, *p = *pp;
88
89         BLK_READBUF(p, end, 4);
90         READ32(sig->si_num_comps);
91         if (sig->si_num_comps == 0) {
92                 BL_LOG_ERR("0 components in sig\n");
93                 goto out_err;
94         }
95         if (sig->si_num_comps >= BLOCK_MAX_SIG_COMP) {
96                 BL_LOG_ERR("number of sig comps %i >= BLOCK_MAX_SIG_COMP\n",
97                            sig->si_num_comps);
98                 goto out_err;
99         }
100         for (i = 0; i < sig->si_num_comps; i++) {
101                 struct bl_sig_comp *comp = &sig->si_comps[i];
102
103                 BLK_READBUF(p, end, 12);
104                 READ64(comp->bs_offset);
105                 READ32(siglen);
106                 comp->bs_length = siglen;
107                 BLK_READBUF(p, end, siglen);
108                 /* Note we rely here on fact that sig is used immediately
109                  * for mapping, then thrown away.
110                  */
111                 comp->bs_string = (char *)p;
112                 BL_LOG_INFO("%s: si_comps[%d]: bs_length %d, bs_string %s\n",
113                             __func__, i, siglen,
114                             pretty_sig(comp->bs_string, siglen));
115                 p += ((siglen + 3) >> 2);
116         }
117         *pp = p;
118         return 0;
119  out_err:
120         return -EIO;
121 }
122
123 /*
124  * Read signature from device and compare to sig_comp
125  * return: 0=match, 1=no match, -1=error
126  */
127 static int
128 read_cmp_blk_sig(struct bl_disk *disk, int fd, struct bl_sig_comp *comp)
129 {
130         const char *dev_name = disk->valid_path->full_path;
131         int ret = -1;
132         ssize_t siglen = comp->bs_length;
133         int64_t bs_offset = comp->bs_offset;
134         char *sig = NULL;
135
136         sig = (char *)malloc(siglen);
137         if (!sig) {
138                 BL_LOG_ERR("%s: Out of memory\n", __func__);
139                 goto out;
140         }
141
142         if (bs_offset < 0)
143                 bs_offset += (((int64_t) disk->size) << 9);
144         if (lseek64(fd, bs_offset, SEEK_SET) == -1) {
145                 BL_LOG_ERR("File %s lseek error\n", dev_name);
146                 goto out;
147         }
148
149         if (read(fd, sig, siglen) != siglen) {
150                 BL_LOG_ERR("File %s read error\n", dev_name);
151                 goto out;
152         }
153
154         ret = memcmp(sig, comp->bs_string, siglen);
155         if (!ret)
156                 BL_LOG_INFO("%s: %s sig %s at %lld\n", __func__, dev_name,
157                             pretty_sig(sig, siglen),
158                             (long long)comp->bs_offset);
159
160  out:
161         if (sig)
162                 free(sig);
163         return ret;
164 }
165
166 /*
167  * All signatures in sig must be found on disk for verification.
168  * Returns True if sig matches, False otherwise.
169  */
170 static int verify_sig(struct bl_disk *disk, struct bl_sig *sig)
171 {
172         const char *dev_name = disk->valid_path->full_path;
173         int fd, i, rv;
174
175         fd = open(dev_name, O_RDONLY | O_LARGEFILE);
176         if (fd < 0) {
177                 BL_LOG_ERR("%s: %s could not be opened for read\n", __func__,
178                            dev_name);
179                 return 0;
180         }
181
182         rv = 1;
183
184         for (i = 0; i < sig->si_num_comps; i++) {
185                 if (read_cmp_blk_sig(disk, fd, &sig->si_comps[i])) {
186                         rv = 0;
187                         break;
188                 }
189         }
190
191         if (fd >= 0)
192                 close(fd);
193         return rv;
194 }
195
196 /*
197  * map_sig_to_device()
198  * Given a signature, walk the list of visible disks searching for
199  * a match. Returns True if mapping was done, False otherwise.
200  *
201  * While we're at it, fill in the vol->bv_size.
202  */
203 static int map_sig_to_device(struct bl_sig *sig, struct bl_volume *vol)
204 {
205         int mapped = 0;
206         struct bl_disk *disk;
207
208         /* scan disk list to find out match device */
209         for (disk = visible_disk_list; disk; disk = disk->next) {
210                 /* FIXME: should we use better algorithm for disk scan? */
211                 mapped = verify_sig(disk, sig);
212                 if (mapped) {
213                         vol->param.bv_dev = disk->dev;
214                         vol->bv_size = disk->size;
215                         break;
216                 }
217         }
218         return mapped;
219 }
220
221 /* We are given an array of XDR encoded array indices, each of which should
222  * refer to a previously decoded device.  Translate into a list of pointers
223  * to the appropriate pnfs_blk_volume's.
224  */
225 static int set_vol_array(uint32_t **pp, uint32_t *end,
226                          struct bl_volume *vols, int working)
227 {
228         int i, index;
229         uint32_t *p = *pp;
230         struct bl_volume **array = vols[working].bv_vols;
231
232         for (i = 0; i < vols[working].bv_vol_n; i++) {
233                 BLK_READBUF(p, end, 4);
234                 READ32(index);
235                 if ((index < 0) || (index >= working)) {
236                         BL_LOG_ERR("set_vol_array: Id %i out of range\n",
237                                    index);
238                         goto out_err;
239                 }
240                 array[i] = &vols[index];
241         }
242         *pp = p;
243         return 0;
244  out_err:
245         return -EIO;
246 }
247
248 static uint64_t sum_subvolume_sizes(struct bl_volume *vol)
249 {
250         int i;
251         uint64_t sum = 0;
252
253         for (i = 0; i < vol->bv_vol_n; i++)
254                 sum += vol->bv_vols[i]->bv_size;
255         return sum;
256 }
257
258 static int
259 decode_blk_volume(uint32_t **pp, uint32_t *end, struct bl_volume *vols, int voln,
260                   int *array_cnt)
261 {
262         int status = 0, j;
263         struct bl_sig sig;
264         uint32_t *p = *pp;
265         struct bl_volume *vol = &vols[voln];
266         uint64_t tmp;
267
268         BLK_READBUF(p, end, 4);
269         READ32(vol->bv_type);
270
271         switch (vol->bv_type) {
272         case BLOCK_VOLUME_SIMPLE:
273                 *array_cnt = 0;
274                 status = decode_blk_signature(&p, end, &sig);
275                 if (status)
276                         return status;
277                 status = map_sig_to_device(&sig, vol);
278                 if (!status) {
279                         BL_LOG_ERR("Could not find disk for device\n");
280                         return -ENXIO;
281                 }
282                 BL_LOG_INFO("%s: simple %d\n", __func__, voln);
283                 status = 0;
284                 break;
285         case BLOCK_VOLUME_SLICE:
286                 BLK_READBUF(p, end, 16);
287                 READ_SECTOR(vol->param.bv_offset);
288                 READ_SECTOR(vol->bv_size);
289                 *array_cnt = vol->bv_vol_n = 1;
290                 BL_LOG_INFO("%s: slice %d\n", __func__, voln);
291                 status = set_vol_array(&p, end, vols, voln);
292                 break;
293         case BLOCK_VOLUME_STRIPE:
294                 BLK_READBUF(p, end, 8);
295                 READ_SECTOR(vol->param.bv_stripe_unit);
296                 off_t stripe_unit = vol->param.bv_stripe_unit;
297                 /* Check limitations imposed by device-mapper */
298                 if ((stripe_unit & (stripe_unit - 1)) != 0
299                     || stripe_unit < (off_t) (PAGE_SIZE >> 9))
300                         return -EIO;
301                 BLK_READBUF(p, end, 4);
302                 READ32(vol->bv_vol_n);
303                 if (!vol->bv_vol_n)
304                         return -EIO;
305                 *array_cnt = vol->bv_vol_n;
306                 BL_LOG_INFO("%s: stripe %d nvols=%d unit=%ld\n", __func__, voln,
307                             vol->bv_vol_n, (long)stripe_unit);
308                 status = set_vol_array(&p, end, vols, voln);
309                 if (status)
310                         return status;
311                 for (j = 1; j < vol->bv_vol_n; j++) {
312                         if (vol->bv_vols[j]->bv_size !=
313                             vol->bv_vols[0]->bv_size) {
314                                 BL_LOG_ERR("varying subvol size\n");
315                                 return -EIO;
316                         }
317                 }
318                 vol->bv_size = vol->bv_vols[0]->bv_size * vol->bv_vol_n;
319                 break;
320         case BLOCK_VOLUME_CONCAT:
321                 BLK_READBUF(p, end, 4);
322                 READ32(vol->bv_vol_n);
323                 if (!vol->bv_vol_n)
324                         return -EIO;
325                 *array_cnt = vol->bv_vol_n;
326                 BL_LOG_INFO("%s: concat %d %d\n", __func__, voln,
327                             vol->bv_vol_n);
328                 status = set_vol_array(&p, end, vols, voln);
329                 if (status)
330                         return status;
331                 vol->bv_size = sum_subvolume_sizes(vol);
332                 break;
333         default:
334                 BL_LOG_ERR("Unknown volume type %i\n", vol->bv_type);
335  out_err:
336                 return -EIO;
337         }
338         *pp = p;
339         return status;
340 }
341
342 uint64_t process_deviceinfo(const char *dev_addr_buf,
343                             unsigned int dev_addr_len,
344                             uint32_t *major, uint32_t *minor)
345 {
346         int num_vols, i, status, count;
347         uint32_t *p, *end;
348         struct bl_volume *vols = NULL, **arrays = NULL, **arrays_ptr = NULL;
349         uint64_t dev = 0;
350
351         p = (uint32_t *) dev_addr_buf;
352         end = (uint32_t *) ((char *)p + dev_addr_len);
353
354         /* Decode block volume */
355         BLK_READBUF(p, end, 4);
356         READ32(num_vols);
357         BL_LOG_INFO("%s: %d vols\n", __func__, num_vols);
358         if (num_vols <= 0)
359                 goto out_err;
360
361         vols = (struct bl_volume *)malloc(num_vols * sizeof(struct bl_volume));
362         if (!vols) {
363                 BL_LOG_ERR("%s: Out of memory\n", __func__);
364                 goto out_err;
365         }
366
367         /* Each volume in vols array needs its own array.  Save time by
368          * allocating them all in one large hunk.  Because each volume
369          * array can only reference previous volumes, and because once
370          * a concat or stripe references a volume, it may never be
371          * referenced again, the volume arrays are guaranteed to fit
372          * in the suprisingly small space allocated.
373          */
374         arrays_ptr = arrays =
375             (struct bl_volume **)malloc(num_vols * 2 *
376                                         sizeof(struct bl_volume *));
377         if (!arrays) {
378                 BL_LOG_ERR("%s: Out of memory\n", __func__);
379                 goto out_err;
380         }
381
382         for (i = 0; i < num_vols; i++) {
383                 vols[i].bv_vols = arrays_ptr;
384                 status = decode_blk_volume(&p, end, vols, i, &count);
385                 if (status)
386                         goto out_err;
387                 arrays_ptr += count;
388         }
389
390         if (p != end) {
391                 BL_LOG_ERR("p is not equal to end!\n");
392                 goto out_err;
393         }
394
395         dev = dm_device_create(vols, num_vols);
396         if (dev) {
397                 *major = MAJOR(dev);
398                 *minor = MINOR(dev);
399         }
400
401  out_err:
402         if (vols)
403                 free(vols);
404         if (arrays)
405                 free(arrays);
406         return dev;
407 }