device-mapper.c revision 1.1.2.1 1 /*
2 * Copyright (c) 1996, 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Adam Hamsik.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /*
31 * I want to say thank you to all people who helped me with this awesome project.
32 */
33
34 #include <sys/types.h>
35 #include <sys/param.h>
36
37 #include <sys/buf.h>
38 #include <sys/conf.h>
39 #include <sys/dkio.h>
40 #include <sys/disk.h>
41 #include <sys/disklabel.h>
42 #include <sys/errno.h>
43 #include <sys/ioctl.h>
44 #include <sys/ioccom.h>
45 #include <sys/kmem.h>
46 #ifdef __LKM__
47 #include <sys/lkm.h>
48 #endif
49
50 #include "netbsd-dm.h"
51 #include "dm.h"
52
53 static dev_type_open(dmopen);
54 static dev_type_close(dmclose);
55 static dev_type_read(dmread);
56 static dev_type_write(dmwrite);
57 static dev_type_ioctl(dmioctl);
58 static dev_type_strategy(dmstrategy);
59 static dev_type_dump(dmdump);
60 static dev_type_size(dmsize);
61
62 /* attach and detach routines */
63 int dmattach(void);
64 int dmdestroy(void);
65
66 static int dm_cmd_to_fun(prop_dictionary_t);
67 static int disk_ioctl_switch(dev_t, u_long, void *);
68 static int dm_ioctl_switch(u_long);
69 static void dmminphys(struct buf*);
70 static void dmgetdisklabel(struct dm_dev*, dev_t);
71 /* ***Variable-definitions*** */
72 const struct bdevsw dm_bdevsw = {
73 dmopen, dmclose, dmstrategy, dmioctl, dmdump, dmsize,
74 D_DISK
75 };
76
77 const struct cdevsw dm_cdevsw = {
78 dmopen, dmclose, dmread, dmwrite, dmioctl,
79 nostop, notty, nopoll, nommap, nokqfilter, D_DISK
80 };
81
82 #ifdef __LKM__
83
84 /* lkm module init routine */
85 int dm_lkmentry(struct lkm_table *, int, int);
86
87 /* lkm module handle routine */
88 static int dm_handle(struct lkm_table *, int);
89
90 MOD_DEV("dm", "dm", &dm_bdevsw, -1, &dm_cdevsw, -1);
91
92 #endif
93
94 /* Info about all devices */
95 struct dm_softc *dm_sc;
96
97 /*
98 * This array is used to translate cmd to function pointer.
99 *
100 * Interface between libdevmapper and lvm2tools uses different
101 * names for one IOCTL call because libdevmapper do another thing
102 * then. When I run "info" or "mknodes" libdevmapper will send same
103 * ioctl to kernel but will do another things in userspace.
104 *
105 */
106 struct cmd_function cmd_fn[] = {
107 {"version", dm_get_version_ioctl},
108 {"targets", dm_list_versions_ioctl},
109 {"create", dm_dev_create_ioctl},
110 {"info", dm_dev_status_ioctl},
111 {"mknodes", dm_dev_status_ioctl},
112 {"names", dm_dev_list_ioctl},
113 {"suspend", dm_dev_suspend_ioctl},
114 {"remove", dm_dev_remove_ioctl},
115 {"rename", dm_dev_rename_ioctl},
116 {"resume", dm_dev_resume_ioctl},
117 {"clear", dm_table_clear_ioctl},
118 {"deps", dm_table_deps_ioctl},
119 {"reload", dm_table_load_ioctl},
120 {"status", dm_table_status_ioctl},
121 {"table", dm_table_status_ioctl},
122 {NULL, NULL}
123 };
124
125 /* attach routine */
126 int
127 dmattach(void)
128 {
129
130 dm_sc = (struct dm_softc *)kmem_alloc(sizeof(struct dm_softc), KM_NOSLEEP);
131
132 if (dm_sc == NULL){
133 aprint_error("Not enough memory for dm device.\n");
134 return(ENOMEM);
135 }
136
137 dm_sc->sc_minor_num = 0;
138 dm_sc->sc_ref_count = 0;
139
140 dm_target_init();
141
142 dm_dev_init();
143
144 dm_pdev_init();
145
146 return 0;
147 }
148
149 /* Destroy routine */
150 int
151 dmdestroy(void)
152 {
153
154 (void)kmem_free(dm_sc,sizeof(struct dm_softc));
155
156 return 0;
157 }
158
159 #ifdef __LKM__
160
161 /* lkm entry for ld */
162 int
163 dm_lkmentry(struct lkm_table *lkmtp, int cmd, int ver)
164 {
165 DISPATCH(lkmtp, cmd, ver, dm_handle, dm_handle, dm_handle);
166 }
167
168 /* handle function for all load/stat/unload actions */
169 static int
170 dm_handle(struct lkm_table *lkmtp, int cmd)
171 {
172
173 int r;
174
175 r=0;
176
177 switch(cmd) {
178
179 case LKM_E_LOAD:
180 aprint_error("Loading dm driver.\n");
181 dmattach();
182 break;
183
184 case LKM_E_UNLOAD:
185 aprint_error("Unloading dm driver.\n");
186 dmdestroy();
187 break;
188
189 case LKM_E_STAT:
190 aprint_error("Opened dm devices: \n");
191 break;
192 }
193
194 return r;
195 }
196
197 #endif
198
199
200 static int
201 dmopen(dev_t dev, int flags, int mode, struct lwp *l)
202 {
203
204 struct dm_dev *dmv;
205
206 if ((dmv = dm_dev_lookup_minor(minor(dev))) != NULL) {
207 if (dmv->dm_dk == NULL)
208 dmgetdisklabel(dmv,dev);
209
210 dmv->ref_cnt++;
211 }
212
213 aprint_verbose("open routine called %d\n",minor(dev));
214
215 return 0;
216 }
217
218
219 static int
220 dmclose(dev_t dev, int flags, int mode, struct lwp *l)
221 {
222 struct dm_dev *dmv;
223
224 if ((dmv = dm_dev_lookup_minor(minor(dev))) != NULL)
225 dmv->ref_cnt--;
226
227 aprint_verbose("CLOSE routine called\n");
228
229 return 0;
230 }
231
232 /*
233 * Called after ioctl call on mapper/control or dm device.
234 */
235
236 static int
237 dmioctl(dev_t dev, const u_long cmd, void *data, int flag, struct lwp *l)
238 {
239 int r;
240 prop_dictionary_t dm_dict_in;
241
242 r = 0;
243
244 if (data == NULL)
245 return(EINVAL);
246
247 if (disk_ioctl_switch(dev,cmd,data) != 0) {
248 struct plistref *pref = (struct plistref *) data;
249
250 r = prop_dictionary_copyin_ioctl(pref, cmd, &dm_dict_in);
251 if (r)
252 return r;
253
254 dm_check_version(dm_dict_in);
255
256 /* call cmd selected function */
257 r = dm_ioctl_switch(cmd);
258 if (r < 0)
259 goto out;
260
261 char *xml;
262 xml = prop_dictionary_externalize(dm_dict_in);
263 aprint_verbose("%s\n",xml);
264
265 r = dm_cmd_to_fun(dm_dict_in);
266 if (r != 0)
267 goto out;
268
269 r = prop_dictionary_copyout_ioctl(pref, cmd, dm_dict_in);
270 }
271
272 out:
273 return r;
274 }
275
276 static int
277 dm_cmd_to_fun(prop_dictionary_t dm_dict){
278 int i,len,slen;
279 int r;
280 const char *command;
281
282 r = 0;
283
284 (void)prop_dictionary_get_cstring_nocopy(dm_dict,DM_IOCTL_COMMAND,&command);
285
286 len = strlen(command);
287
288 for(i=0;cmd_fn[i].cmd != NULL;i++){
289 slen = strlen(cmd_fn[i].cmd);
290
291 if (len != slen)
292 continue;
293
294 if ((strncmp(command,cmd_fn[i].cmd,slen)) == 0) {
295 aprint_verbose("ioctl command: %s\n",command);
296 r = cmd_fn[i].fn(dm_dict);
297 break;
298 }
299 }
300
301 return r;
302 }
303
304 /* Call apropriate ioctl handler function. */
305 static int
306 dm_ioctl_switch(u_long cmd)
307 {
308 int r;
309
310 r = 0;
311
312 switch(cmd) {
313
314 case NETBSD_DM_IOCTL:
315 aprint_verbose("NetBSD_DM_IOCTL called\n");
316 break;
317
318 default:
319 aprint_verbose("unknown ioctl called\n");
320 return EPASSTHROUGH;
321 break; /* NOT REACHED */
322 }
323
324 return r;
325 }
326
327 /*
328 * Check for disk specific ioctls.
329 */
330
331 static int
332 disk_ioctl_switch(dev_t dev, u_long cmd, void *data)
333 {
334 struct dm_dev *dmv;
335
336 if ((dmv = dm_dev_lookup_minor(minor(dev))) == NULL)
337 return 1;
338
339 switch(cmd) {
340
341 case DIOCGWEDGEINFO:
342 {
343 struct dkwedge_info *dkw = (void *) data;
344
345 aprint_verbose("DIOCGWEDGEINFO ioctl called\n");
346
347 strlcpy(dkw->dkw_devname, dmv->name, 16);
348 strlcpy(dkw->dkw_wname, dmv->name, DM_NAME_LEN);
349 strlcpy(dkw->dkw_parent, dmv->name, 16);
350
351 dkw->dkw_offset = 0;
352 dkw->dkw_size = dmsize(dev);
353 strcpy(dkw->dkw_ptype, DKW_PTYPE_FFS);
354
355 break;
356 }
357
358 case DIOCGDINFO:
359 *(struct disklabel *)data = *(dmv->dm_dk->dk_label);
360 break;
361
362 case DIOCGPART:
363 case DIOCWDINFO:
364 case DIOCSDINFO:
365 case DIOCKLABEL:
366 case DIOCWLABEL:
367 case DIOCGDEFLABEL:
368
369 default:
370 aprint_verbose("unknown disk_ioctl called\n");
371 return 1;
372 break; /* NOT REACHED */
373 }
374
375 return 0;
376
377 }
378
379 static void
380 dmstrategy(struct buf *bp)
381 {
382
383 struct dm_dev *dmv;
384 struct dm_table *tbl;
385
386 struct dm_table_entry *table_en;
387
388 struct buf *nestbuf;
389
390 uint64_t table_start;
391 uint64_t table_end;
392
393 uint64_t buf_start;
394 uint64_t buf_len;
395
396 uint64_t start;
397 uint64_t end;
398
399 uint64_t issued_len;
400
401 buf_start = bp->b_blkno * DEV_BSIZE;
402 buf_len = bp->b_bcount;
403
404 tbl = NULL; /* XXX gcc uninitialized */
405
406 table_end = 0;
407
408 issued_len = 0;
409
410 aprint_verbose("dmstrategy routine called %d--%d\n",minor(bp->b_dev),bp->b_bcount);
411
412 if ( (dmv = dm_dev_lookup_minor(minor(bp->b_dev))) == NULL) {
413 bp->b_error = EIO;
414 bp->b_resid = bp->b_bcount;
415 biodone(bp);
416 return;
417 }
418
419 /* Select active table */
420 tbl = &dmv->tables[dmv->cur_active_table];
421
422 /* Nested buffers count down to zero therefore I have
423 to set bp->b_resid to maximal value. */
424 bp->b_resid = bp->b_bcount;
425
426 /*
427 * Find out what tables I want to select.
428 */
429 SLIST_FOREACH(table_en, tbl, next)
430 {
431
432 /* I need need number of bytes not blocks. */
433 table_start = table_en->start * DEV_BSIZE;
434 /* I have to sub 1 from table_en->length to prevent off by one error */
435 table_end = table_start + (table_en->length)* DEV_BSIZE;
436
437 start = MAX(table_start, buf_start);
438
439 end = MIN(table_end, buf_start + buf_len);
440
441 aprint_debug("----------------------------------------\n");
442 aprint_debug("table_start %010" PRIu64", table_end %010" PRIu64 "\n",table_start,
443 table_end);
444 aprint_debug("buf_start %010" PRIu64", buf_len %010" PRIu64"\n",buf_start,buf_len);
445 aprint_debug("start-buf_start %010"PRIu64", end %010"PRIu64"\n",start - buf_start,
446 end);
447 aprint_debug("end-start %010" PRIu64 "\n", end - start);
448 aprint_debug("\n----------------------------------------\n");
449
450 if (start < end) {
451 /* create nested buffer */
452 nestbuf = getiobuf(NULL, true);
453
454 nestiobuf_setup(bp, nestbuf, start - buf_start, (end-start));
455
456 issued_len += end-start;
457
458 /* I need number of blocks. */
459 nestbuf->b_blkno = (start - table_start) / DEV_BSIZE;
460
461 table_en->target->strategy(table_en, nestbuf);
462 }
463 }
464
465 if (issued_len < buf_len)
466 nestiobuf_done(bp, buf_len - issued_len, EINVAL);
467
468 return;
469
470 }
471
472
473 static int
474 dmread(dev_t dev, struct uio *uio, int flag)
475 {
476 return (physio(dmstrategy, NULL, dev, B_READ, dmminphys, uio));
477 }
478
479 static int
480 dmwrite(dev_t dev, struct uio *uio, int flag)
481 {
482 return (physio(dmstrategy, NULL, dev, B_WRITE, dmminphys, uio));
483 }
484
485 static int
486 dmdump(dev_t dev, daddr_t blkno, void *va, size_t size)
487 {
488 return ENODEV;
489 }
490
491 static int
492 dmsize(dev_t dev)
493 {
494 struct dm_dev *dmv;
495 struct dm_table *tbl;
496 struct dm_table_entry *table_en;
497
498 uint64_t length;
499
500 length = 0;
501
502 aprint_debug("dmsize routine called %d\n",minor(dev));
503
504 if ( (dmv = dm_dev_lookup_minor(minor(dev))) == NULL)
505 return ENODEV;
506
507 /* Select active table */
508 tbl = &dmv->tables[dmv->cur_active_table];
509
510 /*
511 * Find out what tables I want to select.
512 * if length => rawblkno then we should used that table.
513 */
514 SLIST_FOREACH(table_en, tbl, next)
515 length += table_en->length;
516
517
518 return length;
519 }
520
521 static void
522 dmminphys(struct buf *bp)
523 {
524 bp->b_bcount = MIN(bp->b_bcount, MAXPHYS);
525 }
526 /*
527 * Load the label information on the named device
528 * Actually fabricate a disklabel
529 *
530 * EVENTUALLY take information about different
531 * data tracks from the TOC and put it in the disklabel
532 */
533
534
535 static void
536 dmgetdisklabel(struct dm_dev *dmv, dev_t dev)
537 {
538 struct disklabel *lp = dmv->dm_dk->dk_label;
539 const char *errstring;
540
541 memset(dmv->dm_dk->dk_cpulabel, 0, sizeof(struct cpu_disklabel));
542
543 /*
544 * Call the generic disklabel extraction routine
545 */
546 errstring = readdisklabel(dev, dmstrategy, lp, dmv->dm_dk->dk_cpulabel);
547
548 /* if all went OK, we are passed a NULL error string */
549 if (errstring == NULL)
550 return;
551
552 aprint_debug("\t%s\t %u sectors \n",dmv->name,dmv->dm_dk->dk_label->d_secsize);
553 }
554
555