Imported Upstream version 2.02.79
[platform/upstream/device-mapper.git] / lib / device / dev-cache.c
1 /*
2  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
4  *
5  * This file is part of LVM2.
6  *
7  * This copyrighted material is made available to anyone wishing to use,
8  * modify, copy, or redistribute it subject to the terms and conditions
9  * of the GNU Lesser General Public License v.2.1.
10  *
11  * You should have received a copy of the GNU Lesser General Public License
12  * along with this program; if not, write to the Free Software Foundation,
13  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
14  */
15
16 #include "lib.h"
17 #include "dev-cache.h"
18 #include "lvm-types.h"
19 #include "btree.h"
20 #include "filter.h"
21 #include "filter-persistent.h"
22 #include "toolcontext.h"
23
24 #include <unistd.h>
25 #include <sys/param.h>
26 #include <dirent.h>
27
28 struct dev_iter {
29         struct btree_iter *current;
30         struct dev_filter *filter;
31 };
32
33 struct dir_list {
34         struct dm_list list;
35         char dir[0];
36 };
37
38 static struct {
39         struct dm_pool *mem;
40         struct dm_hash_table *names;
41         struct btree *devices;
42         struct dm_regex *preferred_names_matcher;
43         const char *dev_dir;
44
45         int has_scanned;
46         struct dm_list dirs;
47         struct dm_list files;
48
49 } _cache;
50
51 #define _alloc(x) dm_pool_zalloc(_cache.mem, (x))
52 #define _free(x) dm_pool_free(_cache.mem, (x))
53 #define _strdup(x) dm_pool_strdup(_cache.mem, (x))
54
55 static int _insert(const char *path, int rec);
56
57 struct device *dev_create_file(const char *filename, struct device *dev,
58                                struct str_list *alias, int use_malloc)
59 {
60         int allocate = !dev;
61
62         if (allocate) {
63                 if (use_malloc) {
64                         if (!(dev = dm_malloc(sizeof(*dev)))) {
65                                 log_error("struct device allocation failed");
66                                 return NULL;
67                         }
68                         if (!(alias = dm_malloc(sizeof(*alias)))) {
69                                 log_error("struct str_list allocation failed");
70                                 dm_free(dev);
71                                 return NULL;
72                         }
73                         if (!(alias->str = dm_strdup(filename))) {
74                                 log_error("filename strdup failed");
75                                 dm_free(dev);
76                                 dm_free(alias);
77                                 return NULL;
78                         }
79                         dev->flags = DEV_ALLOCED;
80                 } else {
81                         if (!(dev = _alloc(sizeof(*dev)))) {
82                                 log_error("struct device allocation failed");
83                                 return NULL;
84                         }
85                         if (!(alias = _alloc(sizeof(*alias)))) {
86                                 log_error("struct str_list allocation failed");
87                                 _free(dev);
88                                 return NULL;
89                         }
90                         if (!(alias->str = _strdup(filename))) {
91                                 log_error("filename strdup failed");
92                                 return NULL;
93                         }
94                 }
95         } else if (!(alias->str = dm_strdup(filename))) {
96                 log_error("filename strdup failed");
97                 return NULL;
98         }
99
100         dev->flags |= DEV_REGULAR;
101         dm_list_init(&dev->aliases);
102         dm_list_add(&dev->aliases, &alias->list);
103         dev->end = UINT64_C(0);
104         dev->dev = 0;
105         dev->fd = -1;
106         dev->open_count = 0;
107         dev->error_count = 0;
108         dev->max_error_count = NO_DEV_ERROR_COUNT_LIMIT;
109         dev->block_size = -1;
110         dev->read_ahead = -1;
111         memset(dev->pvid, 0, sizeof(dev->pvid));
112         dm_list_init(&dev->open_list);
113
114         return dev;
115 }
116
117 static struct device *_dev_create(dev_t d)
118 {
119         struct device *dev;
120
121         if (!(dev = _alloc(sizeof(*dev)))) {
122                 log_error("struct device allocation failed");
123                 return NULL;
124         }
125         dev->flags = 0;
126         dm_list_init(&dev->aliases);
127         dev->dev = d;
128         dev->fd = -1;
129         dev->open_count = 0;
130         dev->max_error_count = dev_disable_after_error_count();
131         dev->block_size = -1;
132         dev->read_ahead = -1;
133         dev->end = UINT64_C(0);
134         memset(dev->pvid, 0, sizeof(dev->pvid));
135         dm_list_init(&dev->open_list);
136
137         return dev;
138 }
139
140 void dev_set_preferred_name(struct str_list *sl, struct device *dev)
141 {
142         /*
143          * Don't interfere with ordering specified in config file.
144          */
145         if (_cache.preferred_names_matcher)
146                 return;
147
148         log_debug("%s: New preferred name", sl->str);
149         dm_list_del(&sl->list);
150         dm_list_add_h(&dev->aliases, &sl->list);
151 }
152
153 /*
154  * Check whether path0 or path1 contains the subpath. The path that
155  * *does not* contain the subpath wins (return 0 or 1). If both paths
156  * contain the subpath, return -1. If none of them contains the subpath,
157  * return -2.
158  */
159 static int _builtin_preference(const char *path0, const char *path1,
160                                size_t skip_prefix_count, const char *subpath)
161 {
162         size_t subpath_len;
163         int r0, r1;
164
165         subpath_len = strlen(subpath);
166
167         r0 = !strncmp(path0 + skip_prefix_count, subpath, subpath_len);
168         r1 = !strncmp(path1 + skip_prefix_count, subpath, subpath_len);
169
170         if (!r0 && r1)
171                 /* path0 does not have the subpath - it wins */
172                 return 0;
173         else if (r0 && !r1)
174                 /* path1 does not have the subpath - it wins */
175                 return 1;
176         else if (r0 && r1)
177                 /* both of them have the subpath */
178                 return -1;
179
180         /* no path has the subpath */
181         return -2;
182 }
183
184 static int _apply_builtin_path_preference_rules(const char *path0, const char *path1)
185 {
186         size_t devdir_len;
187         int r;
188
189         devdir_len = strlen(_cache.dev_dir);
190
191         if (!strncmp(path0, _cache.dev_dir, devdir_len) &&
192             !strncmp(path1, _cache.dev_dir, devdir_len)) {
193                 /*
194                  * We're trying to achieve the ordering:
195                  *      /dev/block/ < /dev/dm-* < /dev/disk/ < /dev/mapper/ < anything else
196                  */
197
198                 /* Prefer any other path over /dev/block/ path. */
199                 if ((r = _builtin_preference(path0, path1, devdir_len, "block/")) >= -1)
200                         return r;
201
202                 /* Prefer any other path over /dev/dm-* path. */
203                 if ((r = _builtin_preference(path0, path1, devdir_len, "dm-")) >= -1)
204                         return r;
205
206                 /* Prefer any other path over /dev/disk/ path. */
207                 if ((r = _builtin_preference(path0, path1, devdir_len, "disk/")) >= -1)
208                         return r;
209
210                 /* Prefer any other path over /dev/mapper/ path. */
211                 if ((r = _builtin_preference(path0, path1, 0, dm_dir())) >= -1)
212                         return r;
213         }
214
215         return -1;
216 }
217
218 /* Return 1 if we prefer path1 else return 0 */
219 static int _compare_paths(const char *path0, const char *path1)
220 {
221         int slash0 = 0, slash1 = 0;
222         int m0, m1;
223         const char *p;
224         char p0[PATH_MAX], p1[PATH_MAX];
225         char *s0, *s1;
226         struct stat stat0, stat1;
227         int r;
228
229         /*
230          * FIXME Better to compare patterns one-at-a-time against all names.
231          */
232         if (_cache.preferred_names_matcher) {
233                 m0 = dm_regex_match(_cache.preferred_names_matcher, path0);
234                 m1 = dm_regex_match(_cache.preferred_names_matcher, path1);
235
236                 if (m0 != m1) {
237                         if (m0 < 0)
238                                 return 1;
239                         if (m1 < 0)
240                                 return 0;
241                         if (m0 < m1)
242                                 return 1;
243                         if (m1 < m0)
244                                 return 0;
245                 }
246         }
247
248         /* Apply built-in preference rules first. */
249         if ((r = _apply_builtin_path_preference_rules(path0, path1)) >= 0)
250                 return r;
251
252         /* Return the path with fewer slashes */
253         for (p = path0; p++; p = (const char *) strchr(p, '/'))
254                 slash0++;
255
256         for (p = path1; p++; p = (const char *) strchr(p, '/'))
257                 slash1++;
258
259         if (slash0 < slash1)
260                 return 0;
261         if (slash1 < slash0)
262                 return 1;
263
264         strncpy(p0, path0, PATH_MAX);
265         strncpy(p1, path1, PATH_MAX);
266         s0 = &p0[0] + 1;
267         s1 = &p1[0] + 1;
268
269         /* We prefer symlinks - they exist for a reason!
270          * So we prefer a shorter path before the first symlink in the name.
271          * FIXME Configuration option to invert this? */
272         while (s0) {
273                 s0 = strchr(s0, '/');
274                 s1 = strchr(s1, '/');
275                 if (s0) {
276                         *s0 = '\0';
277                         *s1 = '\0';
278                 }
279                 if (lstat(p0, &stat0)) {
280                         log_sys_very_verbose("lstat", p0);
281                         return 1;
282                 }
283                 if (lstat(p1, &stat1)) {
284                         log_sys_very_verbose("lstat", p1);
285                         return 0;
286                 }
287                 if (S_ISLNK(stat0.st_mode) && !S_ISLNK(stat1.st_mode))
288                         return 0;
289                 if (!S_ISLNK(stat0.st_mode) && S_ISLNK(stat1.st_mode))
290                         return 1;
291                 if (s0) {
292                         *s0++ = '/';
293                         *s1++ = '/';
294                 }
295         }
296
297         /* ASCII comparison */
298         if (strcmp(path0, path1) < 0)
299                 return 0;
300         else
301                 return 1;
302 }
303
304 static int _add_alias(struct device *dev, const char *path)
305 {
306         struct str_list *sl = _alloc(sizeof(*sl));
307         struct str_list *strl;
308         const char *oldpath;
309         int prefer_old = 1;
310
311         if (!sl)
312                 return_0;
313
314         /* Is name already there? */
315         dm_list_iterate_items(strl, &dev->aliases) {
316                 if (!strcmp(strl->str, path)) {
317                         log_debug("%s: Already in device cache", path);
318                         return 1;
319                 }
320         }
321
322         if (!(sl->str = dm_pool_strdup(_cache.mem, path)))
323                 return_0;
324
325         if (!dm_list_empty(&dev->aliases)) {
326                 oldpath = dm_list_item(dev->aliases.n, struct str_list)->str;
327                 prefer_old = _compare_paths(path, oldpath);
328                 log_debug("%s: Aliased to %s in device cache%s",
329                           path, oldpath, prefer_old ? "" : " (preferred name)");
330
331         } else
332                 log_debug("%s: Added to device cache", path);
333
334         if (prefer_old)
335                 dm_list_add(&dev->aliases, &sl->list);
336         else
337                 dm_list_add_h(&dev->aliases, &sl->list);
338
339         return 1;
340 }
341
342 /*
343  * Either creates a new dev, or adds an alias to
344  * an existing dev.
345  */
346 static int _insert_dev(const char *path, dev_t d)
347 {
348         struct device *dev;
349         static dev_t loopfile_count = 0;
350         int loopfile = 0;
351
352         /* Generate pretend device numbers for loopfiles */
353         if (!d) {
354                 if (dm_hash_lookup(_cache.names, path))
355                         return 1;
356                 d = ++loopfile_count;
357                 loopfile = 1;
358         }
359
360         /* is this device already registered ? */
361         if (!(dev = (struct device *) btree_lookup(_cache.devices,
362                                                    (uint32_t) d))) {
363                 /* create new device */
364                 if (loopfile) {
365                         if (!(dev = dev_create_file(path, NULL, NULL, 0)))
366                                 return_0;
367                 } else if (!(dev = _dev_create(d)))
368                         return_0;
369
370                 if (!(btree_insert(_cache.devices, (uint32_t) d, dev))) {
371                         log_error("Couldn't insert device into binary tree.");
372                         _free(dev);
373                         return 0;
374                 }
375         }
376
377         if (!loopfile && !_add_alias(dev, path)) {
378                 log_error("Couldn't add alias to dev cache.");
379                 return 0;
380         }
381
382         if (!dm_hash_insert(_cache.names, path, dev)) {
383                 log_error("Couldn't add name to hash in dev cache.");
384                 return 0;
385         }
386
387         return 1;
388 }
389
390 static char *_join(const char *dir, const char *name)
391 {
392         size_t len = strlen(dir) + strlen(name) + 2;
393         char *r = dm_malloc(len);
394         if (r)
395                 snprintf(r, len, "%s/%s", dir, name);
396
397         return r;
398 }
399
400 /*
401  * Get rid of extra slashes in the path string.
402  */
403 static void _collapse_slashes(char *str)
404 {
405         char *ptr;
406         int was_slash = 0;
407
408         for (ptr = str; *ptr; ptr++) {
409                 if (*ptr == '/') {
410                         if (was_slash)
411                                 continue;
412
413                         was_slash = 1;
414                 } else
415                         was_slash = 0;
416                 *str++ = *ptr;
417         }
418
419         *str = *ptr;
420 }
421
422 static int _insert_dir(const char *dir)
423 {
424         int n, dirent_count, r = 1;
425         struct dirent **dirent;
426         char *path;
427
428         dirent_count = scandir(dir, &dirent, NULL, alphasort);
429         if (dirent_count > 0) {
430                 for (n = 0; n < dirent_count; n++) {
431                         if (dirent[n]->d_name[0] == '.') {
432                                 free(dirent[n]);
433                                 continue;
434                         }
435
436                         if (!(path = _join(dir, dirent[n]->d_name)))
437                                 return_0;
438
439                         _collapse_slashes(path);
440                         r &= _insert(path, 1);
441                         dm_free(path);
442
443                         free(dirent[n]);
444                 }
445                 free(dirent);
446         }
447
448         return r;
449 }
450
451 static int _insert_file(const char *path)
452 {
453         struct stat info;
454
455         if (stat(path, &info) < 0) {
456                 log_sys_very_verbose("stat", path);
457                 return 0;
458         }
459
460         if (!S_ISREG(info.st_mode)) {
461                 log_debug("%s: Not a regular file", path);
462                 return 0;
463         }
464
465         if (!_insert_dev(path, 0))
466                 return_0;
467
468         return 1;
469 }
470
471 static int _insert(const char *path, int rec)
472 {
473         struct stat info;
474         int r = 0;
475
476         if (stat(path, &info) < 0) {
477                 log_sys_very_verbose("stat", path);
478                 return 0;
479         }
480
481         if (S_ISDIR(info.st_mode)) {    /* add a directory */
482                 /* check it's not a symbolic link */
483                 if (lstat(path, &info) < 0) {
484                         log_sys_very_verbose("lstat", path);
485                         return 0;
486                 }
487
488                 if (S_ISLNK(info.st_mode)) {
489                         log_debug("%s: Symbolic link to directory", path);
490                         return 0;
491                 }
492
493                 if (rec)
494                         r = _insert_dir(path);
495
496         } else {                /* add a device */
497                 if (!S_ISBLK(info.st_mode)) {
498                         log_debug("%s: Not a block device", path);
499                         return 0;
500                 }
501
502                 if (!_insert_dev(path, info.st_rdev))
503                         return_0;
504
505                 r = 1;
506         }
507
508         return r;
509 }
510
511 static void _full_scan(int dev_scan)
512 {
513         struct dir_list *dl;
514
515         if (_cache.has_scanned && !dev_scan)
516                 return;
517
518         dm_list_iterate_items(dl, &_cache.dirs)
519                 _insert_dir(dl->dir);
520
521         dm_list_iterate_items(dl, &_cache.files)
522                 _insert_file(dl->dir);
523
524         _cache.has_scanned = 1;
525         init_full_scan_done(1);
526 }
527
528 int dev_cache_has_scanned(void)
529 {
530         return _cache.has_scanned;
531 }
532
533 void dev_cache_scan(int do_scan)
534 {
535         if (!do_scan)
536                 _cache.has_scanned = 1;
537         else
538                 _full_scan(1);
539 }
540
541 static int _init_preferred_names(struct cmd_context *cmd)
542 {
543         const struct config_node *cn;
544         const struct config_value *v;
545         struct dm_pool *scratch = NULL;
546         const char **regex;
547         unsigned count = 0;
548         int i, r = 0;
549
550         _cache.preferred_names_matcher = NULL;
551
552         if (!(cn = find_config_tree_node(cmd, "devices/preferred_names")) ||
553             cn->v->type == CFG_EMPTY_ARRAY) {
554                 log_very_verbose("devices/preferred_names not found in config file: "
555                                  "using built-in preferences");
556                 return 1;
557         }
558
559         for (v = cn->v; v; v = v->next) {
560                 if (v->type != CFG_STRING) {
561                         log_error("preferred_names patterns must be enclosed in quotes");
562                         return 0;
563                 }
564
565                 count++;
566         }
567
568         if (!(scratch = dm_pool_create("preferred device name matcher", 1024)))
569                 return_0;
570
571         if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count))) {
572                 log_error("Failed to allocate preferred device name "
573                           "pattern list.");
574                 goto out;
575         }
576
577         for (v = cn->v, i = count - 1; v; v = v->next, i--) {
578                 if (!(regex[i] = dm_pool_strdup(scratch, v->v.str))) {
579                         log_error("Failed to allocate a preferred device name "
580                                   "pattern.");
581                         goto out;
582                 }
583         }
584
585         if (!(_cache.preferred_names_matcher =
586                 dm_regex_create(_cache.mem, regex, count))) {
587                 log_error("Preferred device name pattern matcher creation failed.");
588                 goto out;
589         }
590
591         r = 1;
592
593 out:
594         dm_pool_destroy(scratch);
595
596         return r;
597 }
598
599 int dev_cache_init(struct cmd_context *cmd)
600 {
601         _cache.names = NULL;
602         _cache.has_scanned = 0;
603
604         if (!(_cache.mem = dm_pool_create("dev_cache", 10 * 1024)))
605                 return_0;
606
607         if (!(_cache.names = dm_hash_create(128))) {
608                 dm_pool_destroy(_cache.mem);
609                 _cache.mem = 0;
610                 return_0;
611         }
612
613         if (!(_cache.devices = btree_create(_cache.mem))) {
614                 log_error("Couldn't create binary tree for dev-cache.");
615                 goto bad;
616         }
617
618         if (!(_cache.dev_dir = _strdup(cmd->dev_dir))) {
619                 log_error("strdup dev_dir failed.");
620                 goto bad;
621         }
622
623         dm_list_init(&_cache.dirs);
624         dm_list_init(&_cache.files);
625
626         if (!_init_preferred_names(cmd))
627                 goto_bad;
628
629         return 1;
630
631       bad:
632         dev_cache_exit();
633         return 0;
634 }
635
636 static void _check_closed(struct device *dev)
637 {
638         if (dev->fd >= 0)
639                 log_error("Device '%s' has been left open.", dev_name(dev));
640 }
641
642 static void _check_for_open_devices(void)
643 {
644         dm_hash_iter(_cache.names, (dm_hash_iterate_fn) _check_closed);
645 }
646
647 void dev_cache_exit(void)
648 {
649         if (_cache.names)
650                 _check_for_open_devices();
651
652         if (_cache.preferred_names_matcher)
653                 _cache.preferred_names_matcher = NULL;
654
655         if (_cache.mem) {
656                 dm_pool_destroy(_cache.mem);
657                 _cache.mem = NULL;
658         }
659
660         if (_cache.names) {
661                 dm_hash_destroy(_cache.names);
662                 _cache.names = NULL;
663         }
664
665         _cache.devices = NULL;
666         _cache.has_scanned = 0;
667         dm_list_init(&_cache.dirs);
668         dm_list_init(&_cache.files);
669 }
670
671 int dev_cache_add_dir(const char *path)
672 {
673         struct dir_list *dl;
674         struct stat st;
675
676         if (stat(path, &st)) {
677                 log_error("Ignoring %s: %s", path, strerror(errno));
678                 /* But don't fail */
679                 return 1;
680         }
681
682         if (!S_ISDIR(st.st_mode)) {
683                 log_error("Ignoring %s: Not a directory", path);
684                 return 1;
685         }
686
687         if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) {
688                 log_error("dir_list allocation failed");
689                 return 0;
690         }
691
692         strcpy(dl->dir, path);
693         dm_list_add(&_cache.dirs, &dl->list);
694         return 1;
695 }
696
697 int dev_cache_add_loopfile(const char *path)
698 {
699         struct dir_list *dl;
700         struct stat st;
701
702         if (stat(path, &st)) {
703                 log_error("Ignoring %s: %s", path, strerror(errno));
704                 /* But don't fail */
705                 return 1;
706         }
707
708         if (!S_ISREG(st.st_mode)) {
709                 log_error("Ignoring %s: Not a regular file", path);
710                 return 1;
711         }
712
713         if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) {
714                 log_error("dir_list allocation failed for file");
715                 return 0;
716         }
717
718         strcpy(dl->dir, path);
719         dm_list_add(&_cache.files, &dl->list);
720         return 1;
721 }
722
723 /* Check cached device name is still valid before returning it */
724 /* This should be a rare occurrence */
725 /* set quiet if the cache is expected to be out-of-date */
726 /* FIXME Make rest of code pass/cache struct device instead of dev_name */
727 const char *dev_name_confirmed(struct device *dev, int quiet)
728 {
729         struct stat buf;
730         const char *name;
731         int r;
732
733         if ((dev->flags & DEV_REGULAR))
734                 return dev_name(dev);
735
736         while ((r = stat(name = dm_list_item(dev->aliases.n,
737                                           struct str_list)->str, &buf)) ||
738                (buf.st_rdev != dev->dev)) {
739                 if (r < 0) {
740                         if (quiet)
741                                 log_sys_debug("stat", name);
742                         else
743                                 log_sys_error("stat", name);
744                 }
745                 if (quiet)
746                         log_debug("Path %s no longer valid for device(%d,%d)",
747                                   name, (int) MAJOR(dev->dev),
748                                   (int) MINOR(dev->dev));
749                 else
750                         log_error("Path %s no longer valid for device(%d,%d)",
751                                   name, (int) MAJOR(dev->dev),
752                                   (int) MINOR(dev->dev));
753
754                 /* Remove the incorrect hash entry */
755                 dm_hash_remove(_cache.names, name);
756
757                 /* Leave list alone if there isn't an alternative name */
758                 /* so dev_name will always find something to return. */
759                 /* Otherwise add the name to the correct device. */
760                 if (dm_list_size(&dev->aliases) > 1) {
761                         dm_list_del(dev->aliases.n);
762                         if (!r)
763                                 _insert(name, 0);
764                         continue;
765                 }
766
767                 /* Scanning issues this inappropriately sometimes. */
768                 log_debug("Aborting - please provide new pathname for what "
769                           "used to be %s", name);
770                 return NULL;
771         }
772
773         return dev_name(dev);
774 }
775
776 struct device *dev_cache_get(const char *name, struct dev_filter *f)
777 {
778         struct stat buf;
779         struct device *d = (struct device *) dm_hash_lookup(_cache.names, name);
780
781         if (d && (d->flags & DEV_REGULAR))
782                 return d;
783
784         /* If the entry's wrong, remove it */
785         if (d && (stat(name, &buf) || (buf.st_rdev != d->dev))) {
786                 dm_hash_remove(_cache.names, name);
787                 d = NULL;
788         }
789
790         if (!d) {
791                 _insert(name, 0);
792                 d = (struct device *) dm_hash_lookup(_cache.names, name);
793                 if (!d) {
794                         _full_scan(0);
795                         d = (struct device *) dm_hash_lookup(_cache.names, name);
796                 }
797         }
798
799         return (d && (!f || (d->flags & DEV_REGULAR) ||
800                       f->passes_filter(f, d))) ? d : NULL;
801 }
802
803 struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
804 {
805         struct dev_iter *di = dm_malloc(sizeof(*di));
806
807         if (!di) {
808                 log_error("dev_iter allocation failed");
809                 return NULL;
810         }
811
812         if (dev_scan && !trust_cache()) {
813                 /* Flag gets reset between each command */
814                 if (!full_scan_done())
815                         persistent_filter_wipe(f); /* Calls _full_scan(1) */
816         } else
817                 _full_scan(0);
818
819         di->current = btree_first(_cache.devices);
820         di->filter = f;
821         di->filter->use_count++;
822
823         return di;
824 }
825
826 void dev_iter_destroy(struct dev_iter *iter)
827 {
828         iter->filter->use_count--;
829         dm_free(iter);
830 }
831
832 static struct device *_iter_next(struct dev_iter *iter)
833 {
834         struct device *d = btree_get_data(iter->current);
835         iter->current = btree_next(iter->current);
836         return d;
837 }
838
839 struct device *dev_iter_get(struct dev_iter *iter)
840 {
841         while (iter->current) {
842                 struct device *d = _iter_next(iter);
843                 if (!iter->filter || (d->flags & DEV_REGULAR) ||
844                     iter->filter->passes_filter(iter->filter, d))
845                         return d;
846         }
847
848         return NULL;
849 }
850
851 void dev_reset_error_count(struct cmd_context *cmd)
852 {
853         struct dev_iter *iter;
854         struct device *dev;
855
856         if (!(iter = dev_iter_create(cmd->filter, 0))) {
857                 log_error("Resetting device error count failed");
858                 return;
859         }
860
861         for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter))
862                 dev->error_count = 0;
863
864         dev_iter_destroy(iter);
865 }
866
867 int dev_fd(struct device *dev)
868 {
869         return dev->fd;
870 }
871
872 const char *dev_name(const struct device *dev)
873 {
874         return (dev) ? dm_list_item(dev->aliases.n, struct str_list)->str :
875             "unknown device";
876 }