]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/blkmapd/device-process.c
Merge branch 'sid'
[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 uint32_t *blk_overflow(uint32_t * p, uint32_t * end, size_t nbytes)
53 {
54         uint32_t *q = p + ((nbytes + 3) >> 2);
55
56         if (q > end || q < p)
57                 return NULL;
58         return p;
59 }
60
61 static int decode_blk_signature(uint32_t **pp, uint32_t * end,
62                                 struct bl_sig *sig)
63 {
64         int i;
65         uint32_t siglen, *p = *pp;
66
67         BLK_READBUF(p, end, 4);
68         READ32(sig->si_num_comps);
69         if (sig->si_num_comps == 0) {
70                 BL_LOG_ERR("0 components in sig\n");
71                 goto out_err;
72         }
73         if (sig->si_num_comps >= BLOCK_MAX_SIG_COMP) {
74                 BL_LOG_ERR("number of sig comps %i >= BLOCK_MAX_SIG_COMP\n",
75                            sig->si_num_comps);
76                 goto out_err;
77         }
78         for (i = 0; i < sig->si_num_comps; i++) {
79                 struct bl_sig_comp *comp = &sig->si_comps[i];
80
81                 BLK_READBUF(p, end, 12);
82                 READ64(comp->bs_offset);
83                 READ32(siglen);
84                 comp->bs_length = siglen;
85                 BLK_READBUF(p, end, siglen);
86                 /* Note we rely here on fact that sig is used immediately
87                  * for mapping, then thrown away.
88                  */
89                 comp->bs_string = (char *)p;
90                 p += ((siglen + 3) >> 2);
91         }
92         *pp = p;
93         return 0;
94  out_err:
95         return -EIO;
96 }
97
98 /*
99  * Read signature from device and compare to sig_comp
100  * return: 0=match, 1=no match, -1=error
101  */
102 static int
103 read_cmp_blk_sig(struct bl_disk *disk, int fd, struct bl_sig_comp *comp)
104 {
105         const char *dev_name = disk->valid_path->full_path;
106         int ret = -1;
107         ssize_t siglen = comp->bs_length;
108         int64_t bs_offset = comp->bs_offset;
109         char *sig = NULL;
110
111         sig = (char *)malloc(siglen);
112         if (!sig) {
113                 BL_LOG_ERR("%s: Out of memory\n", __func__);
114                 goto out;
115         }
116
117         if (bs_offset < 0)
118                 bs_offset += (((int64_t) disk->size) << 9);
119         if (lseek64(fd, bs_offset, SEEK_SET) == -1) {
120                 BL_LOG_ERR("File %s lseek error\n", dev_name);
121                 goto out;
122         }
123
124         if (read(fd, sig, siglen) != siglen) {
125                 BL_LOG_ERR("File %s read error\n", dev_name);
126                 goto out;
127         }
128
129         ret = memcmp(sig, comp->bs_string, siglen);
130
131  out:
132         if (sig)
133                 free(sig);
134         return ret;
135 }
136
137 /*
138  * All signatures in sig must be found on disk for verification.
139  * Returns True if sig matches, False otherwise.
140  */
141 static int verify_sig(struct bl_disk *disk, struct bl_sig *sig)
142 {
143         const char *dev_name = disk->valid_path->full_path;
144         int fd, i, rv;
145
146         fd = open(dev_name, O_RDONLY | O_LARGEFILE);
147         if (fd < 0) {
148                 BL_LOG_ERR("%s: %s could not be opened for read\n", __func__,
149                            dev_name);
150                 return 0;
151         }
152
153         rv = 1;
154
155         for (i = 0; i < sig->si_num_comps; i++) {
156                 if (read_cmp_blk_sig(disk, fd, &sig->si_comps[i])) {
157                         rv = 0;
158                         break;
159                 }
160         }
161
162         if (fd >= 0)
163                 close(fd);
164         return rv;
165 }
166
167 /*
168  * map_sig_to_device()
169  * Given a signature, walk the list of visible disks searching for
170  * a match. Returns True if mapping was done, False otherwise.
171  *
172  * While we're at it, fill in the vol->bv_size.
173  */
174 static int map_sig_to_device(struct bl_sig *sig, struct bl_volume *vol)
175 {
176         int mapped = 0;
177         struct bl_disk *disk;
178
179         /* scan disk list to find out match device */
180         for (disk = visible_disk_list; disk; disk = disk->next) {
181                 /* FIXME: should we use better algorithm for disk scan? */
182                 mapped = verify_sig(disk, sig);
183                 if (mapped) {
184                         vol->param.bv_dev = disk->dev;
185                         vol->bv_size = disk->size;
186                         break;
187                 }
188         }
189         return mapped;
190 }
191
192 /* We are given an array of XDR encoded array indices, each of which should
193  * refer to a previously decoded device.  Translate into a list of pointers
194  * to the appropriate pnfs_blk_volume's.
195  */
196 static int set_vol_array(uint32_t **pp, uint32_t *end,
197                          struct bl_volume *vols, int working)
198 {
199         int i, index;
200         uint32_t *p = *pp;
201         struct bl_volume **array = vols[working].bv_vols;
202
203         for (i = 0; i < vols[working].bv_vol_n; i++) {
204                 BLK_READBUF(p, end, 4);
205                 READ32(index);
206                 if ((index < 0) || (index >= working)) {
207                         BL_LOG_ERR("set_vol_array: Id %i out of range\n",
208                                    index);
209                         goto out_err;
210                 }
211                 array[i] = &vols[index];
212         }
213         *pp = p;
214         return 0;
215  out_err:
216         return -EIO;
217 }
218
219 static uint64_t sum_subvolume_sizes(struct bl_volume *vol)
220 {
221         int i;
222         uint64_t sum = 0;
223
224         for (i = 0; i < vol->bv_vol_n; i++)
225                 sum += vol->bv_vols[i]->bv_size;
226         return sum;
227 }
228
229 static int
230 decode_blk_volume(uint32_t **pp, uint32_t *end, struct bl_volume *vols, int voln,
231                   int *array_cnt)
232 {
233         int status = 0, j;
234         struct bl_sig sig;
235         uint32_t *p = *pp;
236         struct bl_volume *vol = &vols[voln];
237         uint64_t tmp;
238
239         BLK_READBUF(p, end, 4);
240         READ32(vol->bv_type);
241
242         switch (vol->bv_type) {
243         case BLOCK_VOLUME_SIMPLE:
244                 *array_cnt = 0;
245                 status = decode_blk_signature(&p, end, &sig);
246                 if (status)
247                         return status;
248                 status = map_sig_to_device(&sig, vol);
249                 if (!status) {
250                         BL_LOG_ERR("Could not find disk for device\n");
251                         return -ENXIO;
252                 }
253                 BL_LOG_INFO("%s: simple %d\n", __func__, voln);
254                 status = 0;
255                 break;
256         case BLOCK_VOLUME_SLICE:
257                 BLK_READBUF(p, end, 16);
258                 READ_SECTOR(vol->param.bv_offset);
259                 READ_SECTOR(vol->bv_size);
260                 *array_cnt = vol->bv_vol_n = 1;
261                 BL_LOG_INFO("%s: slice %d\n", __func__, voln);
262                 status = set_vol_array(&p, end, vols, voln);
263                 break;
264         case BLOCK_VOLUME_STRIPE:
265                 BLK_READBUF(p, end, 8);
266                 READ_SECTOR(vol->param.bv_stripe_unit);
267                 off_t stripe_unit = vol->param.bv_stripe_unit;
268                 /* Check limitations imposed by device-mapper */
269                 if ((stripe_unit & (stripe_unit - 1)) != 0
270                     || stripe_unit < (off_t) (sysconf(_SC_PAGE_SIZE) >> 9))
271                         return -EIO;
272                 BLK_READBUF(p, end, 4);
273                 READ32(vol->bv_vol_n);
274                 if (!vol->bv_vol_n)
275                         return -EIO;
276                 *array_cnt = vol->bv_vol_n;
277                 BL_LOG_INFO("%s: stripe %d nvols=%d unit=%ld\n", __func__, voln,
278                             vol->bv_vol_n, (long)stripe_unit);
279                 status = set_vol_array(&p, end, vols, voln);
280                 if (status)
281                         return status;
282                 for (j = 1; j < vol->bv_vol_n; j++) {
283                         if (vol->bv_vols[j]->bv_size !=
284                             vol->bv_vols[0]->bv_size) {
285                                 BL_LOG_ERR("varying subvol size\n");
286                                 return -EIO;
287                         }
288                 }
289                 vol->bv_size = vol->bv_vols[0]->bv_size * vol->bv_vol_n;
290                 break;
291         case BLOCK_VOLUME_CONCAT:
292                 BLK_READBUF(p, end, 4);
293                 READ32(vol->bv_vol_n);
294                 if (!vol->bv_vol_n)
295                         return -EIO;
296                 *array_cnt = vol->bv_vol_n;
297                 BL_LOG_INFO("%s: concat %d %d\n", __func__, voln,
298                             vol->bv_vol_n);
299                 status = set_vol_array(&p, end, vols, voln);
300                 if (status)
301                         return status;
302                 vol->bv_size = sum_subvolume_sizes(vol);
303                 break;
304         default:
305                 BL_LOG_ERR("Unknown volume type %i\n", vol->bv_type);
306  out_err:
307                 return -EIO;
308         }
309         *pp = p;
310         return status;
311 }
312
313 uint64_t process_deviceinfo(const char *dev_addr_buf,
314                             unsigned int dev_addr_len,
315                             uint32_t *major, uint32_t *minor)
316 {
317         int num_vols, i, status, count;
318         uint32_t *p, *end;
319         struct bl_volume *vols = NULL, **arrays = NULL, **arrays_ptr = NULL;
320         uint64_t dev = 0;
321
322         p = (uint32_t *) dev_addr_buf;
323         end = (uint32_t *) ((char *)p + dev_addr_len);
324
325         /* Decode block volume */
326         BLK_READBUF(p, end, 4);
327         READ32(num_vols);
328         BL_LOG_INFO("%s: %d vols\n", __func__, num_vols);
329         if (num_vols <= 0)
330                 goto out_err;
331
332         vols = (struct bl_volume *)malloc(num_vols * sizeof(struct bl_volume));
333         if (!vols) {
334                 BL_LOG_ERR("%s: Out of memory\n", __func__);
335                 goto out_err;
336         }
337
338         /* Each volume in vols array needs its own array.  Save time by
339          * allocating them all in one large hunk.  Because each volume
340          * array can only reference previous volumes, and because once
341          * a concat or stripe references a volume, it may never be
342          * referenced again, the volume arrays are guaranteed to fit
343          * in the suprisingly small space allocated.
344          */
345         arrays_ptr = arrays =
346             (struct bl_volume **)malloc(num_vols * 2 *
347                                         sizeof(struct bl_volume *));
348         if (!arrays) {
349                 BL_LOG_ERR("%s: Out of memory\n", __func__);
350                 goto out_err;
351         }
352
353         for (i = 0; i < num_vols; i++) {
354                 vols[i].bv_vols = arrays_ptr;
355                 status = decode_blk_volume(&p, end, vols, i, &count);
356                 if (status)
357                         goto out_err;
358                 arrays_ptr += count;
359         }
360
361         if (p != end) {
362                 BL_LOG_ERR("p is not equal to end!\n");
363                 goto out_err;
364         }
365
366         dev = dm_device_create(vols, num_vols);
367         if (dev) {
368                 *major = MAJOR(dev);
369                 *minor = MINOR(dev);
370         }
371
372  out_err:
373         if (vols)
374                 free(vols);
375         if (arrays)
376                 free(arrays);
377         return dev;
378 }