/* * Common code for checking sessions for mnt use * * Copyright (C) 2014 - 2015 Chris Leech * Copyright (C) 2014 - 2015 Red Hat, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * See the file COPYING included with this distribution for more details. */ #include #include #include #include #include #include #include "initiator.h" #include "transport.h" #include "iscsid.h" #include "iscsi_ipc.h" #include "log.h" #include "iscsi_sysfs.h" #include "iscsi_settings.h" #include "iface.h" #include "host.h" #include "sysdeps.h" #include "iscsi_err.h" #include "iscsi_net_util.h" static struct libmnt_table *mtab, *swaps; static struct libmnt_cache *mntcache; static void libmount_cleanup(void) { mnt_free_table(mtab); mnt_free_table(swaps); mnt_free_cache(mntcache); mtab = NULL; swaps = NULL; mntcache = NULL; } static int libmount_init(void) { mnt_init_debug(0); mtab = mnt_new_table(); swaps = mnt_new_table(); mntcache = mnt_new_cache(); if (!mtab || !swaps || !mntcache) { libmount_cleanup(); return -ENOMEM; } mnt_table_set_cache(mtab, mntcache); mnt_table_set_cache(swaps, mntcache); mnt_table_parse_mtab(mtab, NULL); mnt_table_parse_swaps(swaps, NULL); return 0; } static int trans_filter(const struct dirent *d) { if (!strcmp(".", d->d_name) || !strcmp("..", d->d_name)) return 0; return 1; } static int subdir_filter(const struct dirent *d) { if (!(d->d_type & DT_DIR)) return 0; return trans_filter(d); } static int is_partition(const char *path) { char *devtype; int rc = 0; devtype = sysfs_get_uevent_devtype(path); if (!devtype) return 0; if (strcmp(devtype, "partition") == 0) rc = 1; free(devtype); return rc; } static int blockdev_check_mnts(char *syspath) { struct libmnt_fs *fs; char *devname = NULL; char *_devname = NULL; int rc = 0; devname = sysfs_get_uevent_devname(syspath); if (!devname) goto out; _devname = calloc(1, PATH_MAX); if (!_devname) goto out; snprintf(_devname, PATH_MAX, "/dev/%s", devname); fs = mnt_table_find_source(mtab, _devname, MNT_ITER_FORWARD); if (fs) { rc = 1; goto out; } fs = mnt_table_find_source(swaps, _devname, MNT_ITER_FORWARD); if (fs) rc = 1; out: free(devname); free(_devname); return rc; } static int count_device_users(char *syspath); static int blockdev_get_partitions(char *syspath) { struct dirent **parts = NULL; int n, i; int count = 0; n = scandir(syspath, &parts, subdir_filter, alphasort); for (i = 0; i < n; i++) { char *newpath; newpath = calloc(1, PATH_MAX); if (!newpath) continue; snprintf(newpath, PATH_MAX, "%s/%s", syspath, parts[i]->d_name); free(parts[i]); if (is_partition(newpath)) { count += count_device_users(newpath); } free(newpath); } free(parts); return count; } static int blockdev_get_holders(char *syspath) { char *path = NULL; struct dirent **holds = NULL; int n, i; int count = 0; path = calloc(1, PATH_MAX); if (!path) return 0; snprintf(path, PATH_MAX, "%s/holders", syspath); n = scandir(path, &holds, trans_filter, alphasort); for (i = 0; i < n; i++) { char *newpath; char *rp; newpath = calloc(1, PATH_MAX); if (!newpath) continue; snprintf(newpath, PATH_MAX, "%s/%s", path, holds[i]->d_name); free(holds[i]); rp = realpath(newpath, NULL); if (rp) count += count_device_users(rp); free(newpath); free(rp); } free(path); free(holds); return count; } static int count_device_users(char *syspath) { int count = 0; count += blockdev_check_mnts(syspath); count += blockdev_get_partitions(syspath); count += blockdev_get_holders(syspath); return count; }; static void device_in_use(void *data, int host_no, int target, int lun) { char *syspath = NULL; char *devname = NULL; int *count = data; devname = iscsi_sysfs_get_blockdev_from_lun(host_no, target, lun); if (!devname) goto out; syspath = calloc(1, PATH_MAX); if (!syspath) goto out; snprintf(syspath, PATH_MAX, "/sys/class/block/%s", devname); *count += count_device_users(syspath); out: free(syspath); free(devname); } int session_in_use(int sid) { int host_no = -1, err = 0; int count = 0; if (libmount_init()) { log_error("Failed to initialize libmount, " "not checking for active mounts on session [%d].", sid); return 0; } host_no = iscsi_sysfs_get_host_no_from_sid(sid, &err); if (!err) iscsi_sysfs_for_each_device(&count, host_no, sid, device_in_use); libmount_cleanup(); return count; }