From 406fc5100dac8d225a315a6def6be8d628f34e24 Mon Sep 17 00:00:00 2001 From: Toomas Soome Date: Fri, 23 Oct 2015 09:36:11 +0300 Subject: [PATCH] 6602 lofi should support labeled devices Reviewed by: Igor Kozhukhov Reviewed by: Yuri Pankov Reviewed by: Garrett D'Amore Reviewed by: Robert Mustacchi Approved by: Dan McDonald --- usr/src/cmd/devfsadm/devfsadm.c | 76 +- usr/src/cmd/devfsadm/disk_link.c | 66 +- usr/src/cmd/devfsadm/lofi_link.c | 29 +- usr/src/cmd/format/menu_fdisk.c | 20 + usr/src/cmd/lofiadm/main.c | 159 ++- .../brand/solaris10/s10_brand/common/s10_brand.c | 7 +- usr/src/man/man1m/lofiadm.1m | 1406 ++++++++----------- usr/src/uts/common/fs/vfs.c | 33 +- usr/src/uts/common/io/cmlb.c | 114 +- usr/src/uts/common/io/lofi.c | 1482 +++++++++++++++----- usr/src/uts/common/os/log_sysevent.c | 59 +- usr/src/uts/common/sys/cmlb.h | 18 + usr/src/uts/common/sys/cmlb_impl.h | 27 +- usr/src/uts/common/sys/lofi.h | 41 +- usr/src/uts/common/sys/vfs.h | 3 +- usr/src/uts/common/sys/vtoc.h | 13 +- usr/src/uts/intel/lofi/Makefile | 4 +- usr/src/uts/sparc/lofi/Makefile | 4 +- 18 files changed, 2270 insertions(+), 1291 deletions(-) rewrite usr/src/man/man1m/lofiadm.1m (61%) diff --git a/usr/src/cmd/devfsadm/devfsadm.c b/usr/src/cmd/devfsadm/devfsadm.c index 448554a5e0..7d7904e9c0 100644 --- a/usr/src/cmd/devfsadm/devfsadm.c +++ b/usr/src/cmd/devfsadm/devfsadm.c @@ -20,6 +20,7 @@ */ /* + * Copyright 2016 Toomas Soome * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. */ @@ -3289,7 +3290,7 @@ rm_parent_dir_if_empty(char *pathname) */ void devfsadm_rm_stale_links(char *dir_re, char *valid_link, di_node_t node, - di_minor_t minor) + di_minor_t minor) { link_t *link; linkhead_t *head; @@ -4837,7 +4838,7 @@ get_component(char *str, const char *comp_str) */ int devfsadm_enumerate_int(char *devfs_path, int index, char **buf, - devfsadm_enumerate_t rules[], int nrules) + devfsadm_enumerate_t rules[], int nrules) { return (find_enum_id(rules, nrules, devfs_path, index, "0", INTEGER, buf, 0)); @@ -4857,7 +4858,7 @@ disk_enumerate_int(char *devfs_path, int index, char **buf, */ static int devfsadm_enumerate_int_start(char *devfs_path, int index, char **buf, - devfsadm_enumerate_t rules[], int nrules, char *start) + devfsadm_enumerate_t rules[], int nrules, char *start) { return (find_enum_id(rules, nrules, devfs_path, index, start, INTEGER, buf, 0)); @@ -4869,7 +4870,7 @@ devfsadm_enumerate_int_start(char *devfs_path, int index, char **buf, */ int devfsadm_enumerate_char(char *devfs_path, int index, char **buf, - devfsadm_enumerate_t rules[], int nrules) + devfsadm_enumerate_t rules[], int nrules) { return (find_enum_id(rules, nrules, devfs_path, index, "a", LETTER, buf, 0)); @@ -4881,7 +4882,7 @@ devfsadm_enumerate_char(char *devfs_path, int index, char **buf, */ int devfsadm_enumerate_char_start(char *devfs_path, int index, char **buf, - devfsadm_enumerate_t rules[], int nrules, char *start) + devfsadm_enumerate_t rules[], int nrules, char *start) { return (find_enum_id(rules, nrules, devfs_path, index, start, LETTER, buf, 0)); @@ -4898,8 +4899,8 @@ devfsadm_enumerate_char_start(char *devfs_path, int index, char **buf, */ static int find_enum_id(devfsadm_enumerate_t rules[], int nrules, - char *devfs_path, int index, char *min, int type, char **buf, - int multiple) + char *devfs_path, int index, char *min, int type, char **buf, + int multiple) { numeral_t *matchnp; numeral_t *numeral; @@ -4999,7 +5000,7 @@ find_enum_id(devfsadm_enumerate_t rules[], int nrules, */ static int lookup_enum_cache(numeral_set_t *set, char *cmp_str, - devfsadm_enumerate_t rules[], int index, numeral_t **matchnpp) + devfsadm_enumerate_t rules[], int index, numeral_t **matchnpp) { int matchcount = 0, rv = -1; int uncached; @@ -5390,7 +5391,7 @@ new_id(numeral_t *numeral, int type, char *min) static int enumerate_parse(char *rsvstr, char *path_left, numeral_set_t *setp, - devfsadm_enumerate_t rules[], int index) + devfsadm_enumerate_t rules[], int index) { char *slash1 = NULL; char *slash2 = NULL; @@ -5506,7 +5507,7 @@ out: */ static void enumerate_recurse(char *current_dir, char *path_left, numeral_set_t *setp, - devfsadm_enumerate_t rules[], int index) + devfsadm_enumerate_t rules[], int index) { char *slash; char *new_path; @@ -5661,7 +5662,7 @@ create_reserved_numeral(numeral_set_t *setp, char *numeral_id) */ static void create_cached_numeral(char *path, numeral_set_t *setp, char *numeral_id, - devfsadm_enumerate_t rules[], int index) + devfsadm_enumerate_t rules[], int index) { char linkbuf[PATH_MAX + 1]; char lpath[PATH_MAX + 1]; @@ -5838,7 +5839,7 @@ devfsadm_copy(void) /*ARGSUSED*/ static int devfsadm_copy_file(const char *file, const struct stat *stat, - int flags, struct FTW *ftw) + int flags, struct FTW *ftw) { struct stat sp; dev_t newdev; @@ -6290,7 +6291,7 @@ read_devlinktab_file(void) */ static int split_devlinktab_entry(char *entry, char **selector, char **p_link, - char **s_link) + char **s_link) { char *tab; @@ -6726,7 +6727,7 @@ get_anchored_re(char *link, char *anchored_re, char *pattern) static int construct_devlink(char *link, link_list_t *link_build, char *contents, - di_minor_t minor, di_node_t node, char *pattern) + di_minor_t minor, di_node_t node, char *pattern) { int counter_offset = -1; devfsadm_enumerate_t rules[1] = {NULL}; @@ -7133,7 +7134,7 @@ dequote(char *src) */ static void getattr(char *phy_path, char *aminor, int spectype, dev_t dev, mode_t *mode, - uid_t *uid, gid_t *gid) + uid_t *uid, gid_t *gid) { char devname[PATH_MAX + 1]; char *node_name; @@ -8219,6 +8220,26 @@ build_event_attributes(char *class, char *subclass, char *node_path, goto out; if (strcmp(subclass, ESC_DISK) == 0) { + /* + * While we're removing labeled lofi device, we will receive + * event for every registered minor device and lastly, + * an event with minor set to NULL, as in following example: + * class: EC_dev_remove subclass: disk + * node_path: /pseudo/lofi@1 driver: lofi minor: u,raw + * class: EC_dev_remove subclass: disk + * node_path: /pseudo/lofi@1 driver: lofi minor: NULL + * + * When we receive this last event with minor set to NULL, + * all lofi minor devices are already removed and the call to + * lookup_disk_dev_name() would result in error. + * To prevent name lookup error messages for this case, we + * need to filter out that last event. + */ + if (strcmp(class, EC_DEV_REMOVE) == 0 && + strcmp(driver_name, "lofi") == 0 && minor == NULL) { + nvlist_free(nvl); + return (NULL); + } if ((dev_name = lookup_disk_dev_name(node_path)) == NULL) { dev_name_lookup_err = 1; goto out; @@ -8239,11 +8260,26 @@ build_event_attributes(char *class, char *subclass, char *node_path, * The raw minor node is created or removed after the block * node. Lofi devfs events are dependent on this behavior. * Generate the sysevent only for the raw minor node. + * + * If the lofi mapping is created, we will receive the following + * event: class: EC_dev_add subclass: lofi minor: NULL + * + * As in case of EC_dev_add, the minor is NULL pointer, + * to get device links created, we will need to provide the + * type of minor node for lookup_lofi_dev_name() + * + * If the lofi device is unmapped, we will receive following + * events: + * class: EC_dev_remove subclass: lofi minor: disk + * class: EC_dev_remove subclass: lofi minor: disk,raw + * class: EC_dev_remove subclass: lofi minor: NULL */ - if (strstr(minor, "raw") == NULL) { - if (nvl) { - nvlist_free(nvl); - } + + if (strcmp(class, EC_DEV_ADD) == 0 && minor == NULL) + minor = "disk,raw"; + + if (minor == NULL || strstr(minor, "raw") == NULL) { + nvlist_free(nvl); return (NULL); } if ((dev_name = lookup_lofi_dev_name(node_path, minor)) == @@ -8374,7 +8410,7 @@ process_syseventq() static void build_and_enq_event(char *class, char *subclass, char *node_path, - di_node_t node, char *minor) + di_node_t node, char *minor) { nvlist_t *nvl; diff --git a/usr/src/cmd/devfsadm/disk_link.c b/usr/src/cmd/devfsadm/disk_link.c index 80e75c1694..0baa608912 100644 --- a/usr/src/cmd/devfsadm/disk_link.c +++ b/usr/src/cmd/devfsadm/disk_link.c @@ -19,6 +19,7 @@ * CDDL HEADER END */ /* + * Copyright 2016 Toomas Soome * Copyright 2012 Nexenta Systems, Inc. All rights reserved. * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. @@ -30,11 +31,13 @@ #include #include #include +#include #include #include #include #include #include +#include #define DISK_SUBPATH_MAX 100 #define RM_STALE 0x01 @@ -69,6 +72,7 @@ static void disk_common(di_minor_t minor, di_node_t node, char *disk, int flags); static char *diskctrl(di_node_t node, di_minor_t minor); static int reserved_links_exist(di_node_t node, di_minor_t minor, int nflags); +static void disk_rm_lofi_all(char *file); static devfsadm_create_t disk_cbt[] = { @@ -104,9 +108,12 @@ static devfsadm_create_t disk_cbt[] = { DEVFSADM_CREATE_INIT_V0(disk_cbt); /* - * HOT auto cleanup of disks not desired. + * HOT auto cleanup of disks is done for lofi devices only. */ static devfsadm_remove_t disk_remove_cbt[] = { + { "disk", DISK_LINK_RE, RM_HOT | RM_POST | RM_ALWAYS, + ILEVEL_0, disk_rm_lofi_all + }, { "disk", DISK_LINK_RE, RM_POST, ILEVEL_0, devfsadm_rm_all } @@ -124,6 +131,44 @@ static devlink_re_t disks_re_array[] = { static char *disk_mid = "disk_mid"; static char *modname = "disk_link"; +/* + * Check if link is from lofi by checking path from readlink(). + */ +static int +is_lofi_disk(char *file) +{ + char buf[PATH_MAX + 1]; + char filepath[PATH_MAX]; + char *ptr; + ssize_t size; + + size = snprintf(filepath, sizeof (filepath), "%s/dev/%s", + devfsadm_root_path(), file); + if (size > sizeof (filepath)) + return (0); + + size = readlink(filepath, buf, sizeof (buf) - 1); + if (size == -1) + return (0); + buf[size] = '\0'; + ptr = strchr(buf, '@'); + if (ptr == NULL) + return (0); + ptr[1] = '\0'; + if (strcmp(buf, "../../devices/pseudo/lofi@") != 0) + return (0); + return (1); +} + +/* + * Wrapper around devfsadm_rm_link() for lofi devices. + */ +static void disk_rm_lofi_all(char *file) +{ + if (is_lofi_disk(file)) + devfsadm_rm_link(file); +} + int minor_init() { @@ -137,13 +182,20 @@ static int disk_callback_chan(di_minor_t minor, di_node_t node) { char *addr; - char disk[20]; - uint_t targ; - uint_t lun; + char disk[23]; + char *driver; + uint_t targ = 0; + uint_t lun = 0; + + driver = di_driver_name(node); + if (strcmp(driver, LOFI_DRIVER_NAME) != 0) { + addr = di_bus_addr(node); + (void) sscanf(addr, "%X,%X", &targ, &lun); + } else { + targ = di_instance(node); + } - addr = di_bus_addr(node); - (void) sscanf(addr, "%X,%X", &targ, &lun); - (void) sprintf(disk, "t%dd%d", targ, lun); + (void) snprintf(disk, sizeof (disk), "t%dd%d", targ, lun); disk_common(minor, node, disk, 0); return (DEVFSADM_CONTINUE); diff --git a/usr/src/cmd/devfsadm/lofi_link.c b/usr/src/cmd/devfsadm/lofi_link.c index d86089f0bb..36fbe987d4 100644 --- a/usr/src/cmd/devfsadm/lofi_link.c +++ b/usr/src/cmd/devfsadm/lofi_link.c @@ -19,12 +19,11 @@ * CDDL HEADER END */ /* + * Copyright 2016 Toomas Soome * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include #include @@ -73,16 +72,14 @@ lofi_rm_all(char *link) * For the master device: * /dev/lofictl -> /devices/pseudo/lofi@0:ctl * For each other device - * /dev/lofi/1 -> /devices/pseudo/lofi@0:1 - * /dev/rlofi/1 -> /devices/pseudo/lofi@0:1,raw + * /dev/lofi/1 -> /devices/pseudo/lofi@1:disk + * /dev/rlofi/1 -> /devices/pseudo/lofi@1:disk,raw */ static int lofi(di_minor_t minor, di_node_t node) { - dev_t dev; + int instance; char mn[MAXNAMELEN + 1]; - char blkname[MAXNAMELEN + 1]; - char rawname[MAXNAMELEN + 1]; char path[PATH_MAX + 1]; (void) strcpy(mn, di_minor_name(minor)); @@ -90,18 +87,14 @@ lofi(di_minor_t minor, di_node_t node) if (strcmp(mn, "ctl") == 0) { (void) devfsadm_mklink(LOFI_CTL_NAME, node, minor, 0); } else { - dev = di_minor_devt(minor); - (void) snprintf(blkname, sizeof (blkname), "%d", - (int)minor(dev)); - (void) snprintf(rawname, sizeof (rawname), "%d,raw", - (int)minor(dev)); + instance = di_instance(node); - if (strcmp(mn, blkname) == 0) { - (void) snprintf(path, sizeof (path), "%s/%s", - LOFI_BLOCK_NAME, blkname); - } else if (strcmp(mn, rawname) == 0) { - (void) snprintf(path, sizeof (path), "%s/%s", - LOFI_CHAR_NAME, blkname); + if (strcmp(mn, LOFI_BLOCK_NODE) == 0) { + (void) snprintf(path, sizeof (path), "%s/%d", + LOFI_BLOCK_NAME, instance); + } else if (strcmp(mn, LOFI_CHAR_NODE) == 0) { + (void) snprintf(path, sizeof (path), "%s/%d", + LOFI_CHAR_NAME, instance); } else { return (DEVFSADM_CONTINUE); } diff --git a/usr/src/cmd/format/menu_fdisk.c b/usr/src/cmd/format/menu_fdisk.c index c3d9bcdcac..317954221f 100644 --- a/usr/src/cmd/format/menu_fdisk.c +++ b/usr/src/cmd/format/menu_fdisk.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2016 Toomas Soome */ /* @@ -709,6 +710,16 @@ copy_solaris_part(struct ipart *ipart) } if ((fd = open(buf, O_RDONLY)) < 0) { + /* + * Labeled device support in lofi provides p0 partition on + * both x86 and sparc. However, sparc does not implement fdisk + * partitioning. This workaround will allow format + * to ignore fdisk errors in case of lofi devices. + */ + if (strcmp(cur_disk->disk_dkinfo.dki_cname, "lofi") == 0) { + solaris_offset = 0; + return (0); + } err_print("Error: can't open disk '%s'.\n", buf); return (-1); } @@ -965,6 +976,15 @@ good_fdisk() if (lel(cur_disk->fdisk_part.numsect) > 0) { return (1); } else { + /* + * Labeled device support in lofi provides p0 partition on + * both x86 and sparc. However, sparc does not implement fdisk + * partitioning. This workaround will allow format + * to ignore fdisk errors in case of lofi devices. + */ + if (strcmp(cur_disk->disk_dkinfo.dki_cname, "lofi") == 0) { + return (1); + } err_print("WARNING - "); err_print("This disk may be in use by an application " "that has\n\t modified the fdisk table. Ensure " diff --git a/usr/src/cmd/lofiadm/main.c b/usr/src/cmd/lofiadm/main.c index 542bec8063..781a2d8c0f 100644 --- a/usr/src/cmd/lofiadm/main.c +++ b/usr/src/cmd/lofiadm/main.c @@ -59,6 +59,8 @@ #include #include #include +#include +#include #include "utils.h" #include @@ -68,7 +70,7 @@ #include static const char USAGE[] = - "Usage: %s [-r] -a file [ device ]\n" + "Usage: %s [-r] [-l] -a file [ device ]\n" " %s [-r] -c crypto_algorithm -a file [device]\n" " %s [-r] -c crypto_algorithm -k raw_key_file -a file [device]\n" " %s [-r] -c crypto_algorithm -T [token]:[manuf]:[serial]:key " @@ -218,7 +220,7 @@ static ISzAlloc g_Alloc = { /*ARGSUSED*/ static int lzma_compress(void *src, size_t srclen, void *dst, - size_t *dstlen, int level) + size_t *dstlen, int level) { CLzmaEncProps props; size_t outsize2; @@ -280,14 +282,30 @@ lzma_compress(void *src, size_t srclen, void *dst, static int name_to_minor(const char *devicename) { - int minor; + struct stat st; + + /* + * If devicename does not exist, then devicename contains + * the name of the device to be created. + * Note we only allow non-labeled devices here. + */ + if (stat(devicename, &st)) { + int minor, rv; - if (sscanf(devicename, "/dev/" LOFI_BLOCK_NAME "/%d", &minor) == 1) { - return (minor); + rv = sscanf(devicename, "/dev/" LOFI_BLOCK_NAME "/%d", &minor); + if (rv == 1) + return (minor); + rv = sscanf(devicename, "/dev/" LOFI_CHAR_NAME "/%d", &minor); + if (rv == 1) + return (minor); + + return (0); } - if (sscanf(devicename, "/dev/" LOFI_CHAR_NAME "/%d", &minor) == 1) { - return (minor); + + if (st.st_mode & S_IFCHR || st.st_mode & S_IFBLK) { + return (LOFI_MINOR2ID(minor(st.st_rdev))); } + return (0); } @@ -303,7 +321,32 @@ static int sleeptime = 2; /* number of seconds to sleep between stat's */ static int maxsleep = 120; /* maximum number of seconds to sleep */ static void -wait_until_dev_complete(int minor) +make_blkdevname(struct lofi_ioctl *li, char *path, size_t len) +{ + char *r1, *r2; + size_t l1; + + if (li->li_devpath[0] == '\0') { + if (li->li_labeled) + (void) strlcpy(path, "unknown", len); + else + (void) snprintf(path, len, + "/dev/" LOFI_BLOCK_NAME "/%d", li->li_id); + return; + } + (void) strlcpy(path, li->li_devpath, len); + r1 = strchr(path, 'r'); + l1 = r1 - path; + r2 = strchr(li->li_devpath, 'r'); + (void) strlcpy(r1, r2+1, len - l1); + + if (li->li_labeled) { + (void) strlcat(path, "p0", len); + } +} + +static void +wait_until_dev_complete(struct lofi_ioctl *li) { struct stat64 buf; int cursleep; @@ -311,10 +354,12 @@ wait_until_dev_complete(int minor) char charpath[MAXPATHLEN]; di_devlink_handle_t hdl; - (void) snprintf(blkpath, sizeof (blkpath), "/dev/%s/%d", - LOFI_BLOCK_NAME, minor); - (void) snprintf(charpath, sizeof (charpath), "/dev/%s/%d", - LOFI_CHAR_NAME, minor); + make_blkdevname(li, blkpath, sizeof (blkpath)); + (void) strlcpy(charpath, li->li_devpath, sizeof (charpath)); + + if (li->li_labeled) { + (void) strlcat(charpath, "p0", sizeof (charpath)); + } /* Check if links already present */ if (stat64(blkpath, &buf) == 0 && stat64(charpath, &buf) == 0) @@ -352,20 +397,20 @@ out: * DO NOT use this function if the filename is actually the device name. */ static int -lofi_map_file(int lfd, struct lofi_ioctl li, const char *filename) +lofi_map_file(int lfd, struct lofi_ioctl *li, const char *filename) { int minor; - li.li_minor = 0; - (void) strlcpy(li.li_filename, filename, sizeof (li.li_filename)); - minor = ioctl(lfd, LOFI_MAP_FILE, &li); + li->li_id = 0; + (void) strlcpy(li->li_filename, filename, sizeof (li->li_filename)); + minor = ioctl(lfd, LOFI_MAP_FILE, li); if (minor == -1) { if (errno == ENOTSUP) warn(gettext("encrypting compressed files is " "unsupported")); die(gettext("could not map file %s"), filename); } - wait_until_dev_complete(minor); + wait_until_dev_complete(li); return (minor); } @@ -375,11 +420,14 @@ lofi_map_file(int lfd, struct lofi_ioctl li, const char *filename) */ static void add_mapping(int lfd, const char *devicename, const char *filename, - mech_alias_t *cipher, const char *rkey, size_t rksz, boolean_t rdonly) + mech_alias_t *cipher, const char *rkey, size_t rksz, boolean_t rdonly, + boolean_t label) { struct lofi_ioctl li; + bzero(&li, sizeof (li)); li.li_readonly = rdonly; + li.li_labeled = label; li.li_crypto_enabled = B_FALSE; if (cipher != NULL) { @@ -409,17 +457,22 @@ add_mapping(int lfd, const char *devicename, const char *filename, if (devicename == NULL) { int minor; + char path[MAXPATHLEN]; /* pick one via the driver */ - minor = lofi_map_file(lfd, li, filename); - /* if mapping succeeds, print the one picked */ - (void) printf("/dev/%s/%d\n", LOFI_BLOCK_NAME, minor); + minor = lofi_map_file(lfd, &li, filename); + if (minor > 0) { + make_blkdevname(&li, path, sizeof (path)); + + /* if mapping succeeds, print the one picked */ + (void) printf("%s\n", path); + } return; } /* use device we were given */ - li.li_minor = name_to_minor(devicename); - if (li.li_minor == 0) { + li.li_id = name_to_minor(devicename); + if (li.li_id == 0) { die(gettext("malformed device name %s\n"), devicename); } (void) strlcpy(li.li_filename, filename, sizeof (li.li_filename)); @@ -432,7 +485,7 @@ add_mapping(int lfd, const char *devicename, const char *filename, die(gettext("could not map file %s to %s"), filename, devicename); } - wait_until_dev_complete(li.li_minor); + wait_until_dev_complete(&li); } /* @@ -452,7 +505,7 @@ delete_mapping(int lfd, const char *devicename, const char *filename, /* delete by filename */ (void) strlcpy(li.li_filename, filename, sizeof (li.li_filename)); - li.li_minor = 0; + li.li_id = 0; if (ioctl(lfd, LOFI_UNMAP_FILE, &li) == -1) { die(gettext("could not unmap file %s"), filename); } @@ -460,8 +513,8 @@ delete_mapping(int lfd, const char *devicename, const char *filename, } /* delete by device */ - li.li_minor = name_to_minor(devicename); - if (li.li_minor == 0) { + li.li_id = name_to_minor(devicename); + if (li.li_id == 0) { die(gettext("malformed device name %s\n"), devicename); } if (ioctl(lfd, LOFI_UNMAP_FILE_MINOR, &li) == -1) { @@ -476,22 +529,24 @@ static void print_one_mapping(int lfd, const char *devicename, const char *filename) { struct lofi_ioctl li; + char blkpath[MAXPATHLEN]; if (devicename == NULL) { /* given filename, print devicename */ - li.li_minor = 0; + li.li_id = 0; (void) strlcpy(li.li_filename, filename, sizeof (li.li_filename)); if (ioctl(lfd, LOFI_GET_MINOR, &li) == -1) { die(gettext("could not find device for %s"), filename); } - (void) printf("/dev/%s/%d\n", LOFI_BLOCK_NAME, li.li_minor); + make_blkdevname(&li, blkpath, sizeof (blkpath)); + (void) printf("%s\n", blkpath); return; } /* given devicename, print filename */ - li.li_minor = name_to_minor(devicename); - if (li.li_minor == 0) { + li.li_id = name_to_minor(devicename); + if (li.li_id == 0) { die(gettext("malformed device name %s\n"), devicename); } if (ioctl(lfd, LOFI_GET_FILENAME, &li) == -1) { @@ -512,24 +567,23 @@ print_mappings(int fd) char path[MAXPATHLEN]; char options[MAXPATHLEN] = { 0 }; - li.li_minor = 0; + li.li_id = 0; if (ioctl(fd, LOFI_GET_MAXMINOR, &li) == -1) { die("ioctl"); } - maxminor = li.li_minor; + maxminor = li.li_id; (void) printf(FORMAT, gettext("Block Device"), gettext("File"), gettext("Options")); for (minor = 1; minor <= maxminor; minor++) { - li.li_minor = minor; + li.li_id = minor; if (ioctl(fd, LOFI_GET_FILENAME, &li) == -1) { if (errno == ENXIO) continue; warn("ioctl"); break; } - (void) snprintf(path, sizeof (path), "/dev/%s/%d", - LOFI_BLOCK_NAME, minor); + make_blkdevname(&li, path, sizeof (path)); options[0] = '\0'; @@ -544,14 +598,22 @@ print_mappings(int fd) gettext("Compressed(%s)"), li.li_algorithm); if (li.li_readonly) { if (strlen(options) != 0) { - (void) strlcat(options, ",", sizeof (options)); - (void) strlcat(options, "Readonly", + (void) strlcat(options, ",Readonly", sizeof (options)); } else { (void) snprintf(options, sizeof (options), gettext("Readonly")); } } + if (li.li_labeled) { + if (strlen(options) != 0) { + (void) strlcat(options, ",Labeled", + sizeof (options)); + } else { + (void) snprintf(options, sizeof (options), + gettext("Labeled")); + } + } if (strlen(options) == 0) (void) snprintf(options, sizeof (options), "-"); @@ -1304,7 +1366,7 @@ lofi_uncompress(int lfd, const char *filename) * already mapped. */ li.li_crypto_enabled = B_FALSE; - li.li_minor = 0; + li.li_id = 0; (void) strlcpy(li.li_filename, filename, sizeof (li.li_filename)); if (ioctl(lfd, LOFI_GET_MINOR, &li) != -1) die(gettext("%s must be unmapped before uncompressing"), @@ -1316,7 +1378,7 @@ lofi_uncompress(int lfd, const char *filename) if (statbuf.st_size == 0) return; - minor = lofi_map_file(lfd, li, filename); + minor = lofi_map_file(lfd, &li, filename); (void) snprintf(devicename, sizeof (devicename), "/dev/%s/%d", LOFI_BLOCK_NAME, minor); @@ -1428,7 +1490,7 @@ lofi_compress(int *lfd, const char *filename, int compress_index, * Disallow compressing the file if it is * already mapped */ - lic.li_minor = 0; + lic.li_id = 0; (void) strlcpy(lic.li_filename, filename, sizeof (lic.li_filename)); if (ioctl(*lfd, LOFI_GET_MINOR, &lic) != -1) die(gettext("%s must be unmapped before compressing"), @@ -1845,13 +1907,14 @@ main(int argc, char *argv[]) const char *algname = COMPRESS_ALGORITHM; int openflag; int minor; - int compress_index; + int compress_index; uint32_t segsize = SEGSIZE; static char *lofictl = "/dev/" LOFI_CTL_NAME; boolean_t force = B_FALSE; const char *pname; boolean_t errflag = B_FALSE; boolean_t addflag = B_FALSE; + boolean_t labelflag = B_FALSE; boolean_t rdflag = B_FALSE; boolean_t deleteflag = B_FALSE; boolean_t ephflag = B_FALSE; @@ -1872,7 +1935,7 @@ main(int argc, char *argv[]) (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); - while ((c = getopt(argc, argv, "a:c:Cd:efk:rs:T:U")) != EOF) { + while ((c = getopt(argc, argv, "a:b:c:Cd:efk:lrRs:T:U")) != EOF) { switch (c) { case 'a': addflag = B_TRUE; @@ -1927,6 +1990,9 @@ main(int argc, char *argv[]) need_crypto = B_TRUE; cipher_only = B_FALSE; /* need to unset cipher_only */ break; + case 'l': + labelflag = B_TRUE; + break; case 'r': rdflag = B_TRUE; break; @@ -1960,9 +2026,12 @@ main(int argc, char *argv[]) /* Check for mutually exclusive combinations of options */ if (errflag || (addflag && deleteflag) || + (labelflag && !addflag) || (rdflag && !addflag) || (!addflag && need_crypto) || - ((compressflag || uncompressflag) && (addflag || deleteflag))) + (need_crypto && labelflag) || + ((compressflag || uncompressflag) && + (labelflag || addflag || deleteflag))) usage(pname); /* ephemeral key, and key from either file or token are incompatible */ @@ -2079,7 +2148,7 @@ main(int argc, char *argv[]) */ if (addflag) add_mapping(lfd, devicename, filename, cipher, rkey, rksz, - rdflag); + rdflag, labelflag); else if (compressflag) lofi_compress(&lfd, filename, compress_index, segsize); else if (uncompressflag) diff --git a/usr/src/lib/brand/solaris10/s10_brand/common/s10_brand.c b/usr/src/lib/brand/solaris10/s10_brand/common/s10_brand.c index eb91f5212d..6409c299ca 100644 --- a/usr/src/lib/brand/solaris10/s10_brand/common/s10_brand.c +++ b/usr/src/lib/brand/solaris10/s10_brand/common/s10_brand.c @@ -20,6 +20,7 @@ */ /* + * Copyright 2016 Toomas Soome * Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ @@ -622,7 +623,7 @@ zfs_ioctl(sysret_t *rval, int fdes, int cmd, intptr_t arg) } struct s10_lofi_ioctl { - uint32_t li_minor; + uint32_t li_id; boolean_t li_force; char li_filename[MAXPATHLEN + 1]; }; @@ -652,7 +653,7 @@ lofi_ioctl(sysret_t *rval, int fdes, int cmd, intptr_t arg) bzero(&native_param, sizeof (native_param)); - struct_assign(native_param, s10_param, li_minor); + struct_assign(native_param, s10_param, li_id); struct_assign(native_param, s10_param, li_force); /* @@ -665,7 +666,7 @@ lofi_ioctl(sysret_t *rval, int fdes, int cmd, intptr_t arg) err = __systemcall(rval, SYS_ioctl + 1024, fdes, cmd, &native_param); - struct_assign(s10_param, native_param, li_minor); + struct_assign(s10_param, native_param, li_id); /* li_force is input-only */ bcopy(native_param.li_filename, s10_param.li_filename, diff --git a/usr/src/man/man1m/lofiadm.1m b/usr/src/man/man1m/lofiadm.1m dissimilarity index 61% index 259a269f1c..5eede96b52 100644 --- a/usr/src/man/man1m/lofiadm.1m +++ b/usr/src/man/man1m/lofiadm.1m @@ -1,786 +1,620 @@ -'\" te -.\" Copyright 2013 Nexenta Systems, Inc. All rights reserved. -.\" Copyright (c) 2008, Sun Microsystems, Inc. All Rights Reserved -.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. -.\" See the License for the specific language governing permissions and limitations under the License. When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with -.\" the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] -.TH LOFIADM 1M "Aug 28, 2013" -.SH NAME -lofiadm \- administer files available as block devices through lofi -.SH SYNOPSIS -.LP -.nf -\fBlofiadm\fR [\fB-r\fR] \fB-a\fR \fIfile\fR [\fIdevice\fR] -.fi - -.LP -.nf -\fBlofiadm\fR [\fB-r\fR] \fB-c\fR \fIcrypto_algorithm\fR \fB-a\fR \fIfile\fR [\fIdevice\fR] -.fi - -.LP -.nf -\fBlofiadm\fR [\fB-r\fR] \fB-c\fR \fIcrypto_algorithm\fR \fB-k\fR \fIraw_key_file\fR \fB-a\fR \fIfile\fR [\fIdevice\fR] -.fi - -.LP -.nf -\fBlofiadm\fR [\fB-r\fR] \fB-c\fR \fIcrypto_algorithm\fR \fB-T\fR \fItoken_key\fR \fB-a\fR \fIfile\fR [\fIdevice\fR] -.fi - -.LP -.nf -\fBlofiadm\fR [\fB-r\fR] \fB-c\fR \fIcrypto_algorithm\fR \fB-T\fR \fItoken_key\fR - \fB-k\fR \fIwrapped_key_file\fR \fB-a\fR \fIfile\fR [\fIdevice\fR] -.fi - -.LP -.nf -\fBlofiadm\fR [\fB-r\fR] \fB-c\fR \fIcrypto_algorithm\fR \fB-e\fR \fB-a\fR \fIfile\fR [\fIdevice\fR] -.fi - -.LP -.nf -\fBlofiadm\fR \fB-C\fR \fIalgorithm\fR [\fB-s\fR \fIsegment_size\fR] \fIfile\fR -.fi - -.LP -.nf -\fBlofiadm\fR \fB-d\fR \fIfile\fR | \fIdevice\fR -.fi - -.LP -.nf -\fBlofiadm\fR \fB-U\fR \fIfile\fR -.fi - -.LP -.nf -\fBlofiadm\fR [ \fIfile\fR | \fIdevice\fR] -.fi - -.SH DESCRIPTION -.sp -.LP -\fBlofiadm\fR administers \fBlofi\fR, the loopback file driver. \fBlofi\fR -allows a file to be associated with a block device. That file can then be -accessed through the block device. This is useful when the file contains an -image of some filesystem (such as a floppy or \fBCD-ROM\fR image), because the -block device can then be used with the normal system utilities for mounting, -checking or repairing filesystems. See \fBfsck\fR(1M) and \fBmount\fR(1M). -.sp -.LP -Use \fBlofiadm\fR to add a file as a loopback device, remove such an -association, or print information about the current associations. -.sp -.LP -Encryption and compression options are mutually exclusive on the command line. -Further, an encrypted file cannot be compressed later, nor can a compressed -file be encrypted later. - -In the global zone, \fBlofiadm\fR can be used on both the global -zone devices and all devices owned by other non-global zones on the system. -.sp -.SH OPTIONS -.sp -.LP -The following options are supported: -.sp -.ne 2 -.na -\fB\fB-a\fR \fIfile\fR [\fIdevice\fR]\fR -.ad -.sp .6 -.RS 4n -Add \fIfile\fR as a block device. -.sp -If \fIdevice\fR is not specified, an available device is picked. -.sp -If \fIdevice\fR is specified, \fBlofiadm\fR attempts to assign it to -\fIfile\fR. \fIdevice\fR must be available or \fBlofiadm\fR will fail. The -ability to specify a device is provided for use in scripts that wish to -reestablish a particular set of associations. -.RE - -.sp -.ne 2 -.na -\fB\fB-C\fR {\fIgzip\fR | \fIgzip-N\fR | \fIlzma\fR}\fR -.ad -.sp .6 -.RS 4n -Compress the file with the specified compression algorithm. -.sp -The \fBgzip\fR compression algorithm uses the same compression as the -open-source \fBgzip\fR command. You can specify the \fBgzip\fR level by using -the value \fBgzip-\fR\fIN\fR where \fIN\fR is 6 (fast) or 9 (best compression -ratio). Currently, \fBgzip\fR, without a number, is equivalent to \fBgzip-6\fR -(which is also the default for the \fBgzip\fR command). -.sp -\fIlzma\fR stands for the LZMA (Lempel-Ziv-Markov) compression algorithm. -.sp -Note that you cannot write to a compressed file, nor can you mount a compressed -file read/write. -.RE - -.sp -.ne 2 -.na -\fB\fB-d\fR \fIfile\fR | \fIdevice\fR\fR -.ad -.sp .6 -.RS 4n -Remove an association by \fIfile\fR or \fIdevice\fR name, if the associated -block device is not busy, and deallocates the block device. -.RE - -.sp -.ne 2 -.na -\fB\fB-r\fR -.ad -.sp .6 -.RS 4n -If the \fB-r\fR option is specified before the \fB-a\fR option, the -\fIdevice\fR will be opened read-only. -.RE - -.sp -.ne 2 -.na -\fB\fB-s\fR \fIsegment_size\fR\fR -.ad -.sp .6 -.RS 4n -The segment size to use to divide the file being compressed. \fIsegment_size\fR -can be an integer multiple of 512. -.RE - -.sp -.ne 2 -.na -\fB\fB-U\fR \fIfile\fR\fR -.ad -.sp .6 -.RS 4n -Uncompress a compressed file. -.RE - -.sp -.LP -The following options are used when the file is encrypted: -.sp -.ne 2 -.na -\fB\fB-c\fR \fIcrypto_algorithm\fR\fR -.ad -.sp .6 -.RS 4n -Select the encryption algorithm. The algorithm must be specified when -encryption is enabled because the algorithm is not stored in the disk image. -.sp -If none of \fB-e\fR, \fB-k\fR, or \fB-T\fR is specified, \fBlofiadm\fR prompts -for a passphrase, with a minimum length of eight characters, to be entered . -The passphrase is used to derive a symmetric encryption key using PKCS#5 PBKD2. -.RE - -.sp -.ne 2 -.na -\fB\fB-k\fR \fIraw_key_file\fR | \fIwrapped_key_file\fR\fR -.ad -.sp .6 -.RS 4n -Path to raw or wrapped symmetric encryption key. If a PKCS#11 object is also -given with the \fB-T\fR option, then the key is wrapped by that object. If -\fB-T\fR is not specified, the key is used raw. -.RE - -.sp -.ne 2 -.na -\fB\fB-T\fR \fItoken_key\fR\fR -.ad -.sp .6 -.RS 4n -The key in a PKCS#11 token to use for the encryption or for unwrapping the key -file. -.sp -If \fB-k\fR is also specified, \fB-T\fR identifies the unwrapping key, which -must be an RSA private key. -.RE - -.sp -.ne 2 -.na -\fB\fB-e\fR\fR -.ad -.sp .6 -.RS 4n -Generate an ephemeral symmetric encryption key. -.RE - -.SH OPERANDS -.sp -.LP -The following operands are supported: -.sp -.ne 2 -.na -\fB\fIcrypto_algorithm\fR\fR -.ad -.sp .6 -.RS 4n -One of: \fBaes-128-cbc\fR, \fBaes-192-cbc\fR, \fBaes-256-cbc\fR, -\fBdes3-cbc\fR, \fBblowfish-cbc\fR. -.RE - -.sp -.ne 2 -.na -\fB\fIdevice\fR\fR -.ad -.sp .6 -.RS 4n -Display the file name associated with the block device \fIdevice\fR. -.sp -Without arguments, print a list of the current associations. Filenames must be -valid absolute pathnames. -.sp -When a file is added, it is opened for reading or writing by root. Any -restrictions apply (such as restricted root access over \fBNFS\fR). The file is -held open until the association is removed. It is not actually accessed until -the block device is used, so it will never be written to if the block device is -only opened read-only. - -Note that the filename may appear as "?" if it is not possible to resolve the -path in the current context (for example, if it's an NFS path in a non-global -zone). -.RE - -.sp -.ne 2 -.na -\fB\fIfile\fR\fR -.ad -.sp .6 -.RS 4n -Display the block device associated with \fIfile\fR. -.RE - -.sp -.ne 2 -.na -\fB\fIraw_key_file\fR\fR -.ad -.sp .6 -.RS 4n -Path to a file of the appropriate length, in bits, to use as a raw symmetric -encryption key. -.RE - -.sp -.ne 2 -.na -\fB\fItoken_key\fR\fR -.ad -.sp .6 -.RS 4n -PKCS#11 token object in the format: -.sp -.in +2 -.nf -\fItoken_name\fR:\fImanufacturer_id\fR:\fIserial_number\fR:\fIkey_label\fR -.fi -.in -2 -.sp - -All but the key label are optional and can be empty. For example, to specify a -token object with only its key label \fBMylofiKey\fR, use: -.sp -.in +2 -.nf --T :::MylofiKey -.fi -.in -2 -.sp - -.RE - -.sp -.ne 2 -.na -\fB\fIwrapped_key_file\fR\fR -.ad -.sp .6 -.RS 4n -Path to file containing a symmetric encryption key wrapped by the RSA private -key specified by \fB-T\fR. -.RE - -.SH EXAMPLES -.LP -\fBExample 1 \fRMounting an Existing CD-ROM Image -.sp -.LP -You should ensure that Solaris understands the image before creating the -\fBCD\fR. \fBlofi\fR allows you to mount the image and see if it works. - -.sp -.LP -This example mounts an existing \fBCD-ROM\fR image (\fBsparc.iso\fR), of the -\fBRed Hat 6.0 CD\fR which was downloaded from the Internet. It was created -with the \fBmkisofs\fR utility from the Internet. - -.sp -.LP -Use \fBlofiadm\fR to attach a block device to it: - -.sp -.in +2 -.nf -# \fBlofiadm -a /home/mike_s/RH6.0/sparc.iso\fR -/dev/lofi/1 -.fi -.in -2 -.sp - -.sp -.LP -\fBlofiadm\fR picks the device and prints the device name to the standard -output. You can run \fBlofiadm\fR again by issuing the following command: - -.sp -.in +2 -.nf -# \fBlofiadm\fR -Block Device File Options -/dev/lofi/1 /home/mike_s/RH6.0/sparc.iso - -.fi -.in -2 -.sp - -.sp -.LP -Or, you can give it one name and ask for the other, by issuing the following -command: - -.sp -.in +2 -.nf -# \fBlofiadm /dev/lofi/1\fR -/home/mike_s/RH6.0/sparc.iso -.fi -.in -2 -.sp - -.sp -.LP -Use the \fBmount\fR command to mount the image: - -.sp -.in +2 -.nf -# \fBmount -F hsfs -o ro /dev/lofi/1 /mnt\fR -.fi -.in -2 -.sp - -.sp -.LP -Check to ensure that Solaris understands the image: - -.sp -.in +2 -.nf -# \fBdf -k /mnt\fR -Filesystem kbytes used avail capacity Mounted on -/dev/lofi/1 512418 512418 0 100% /mnt -# \fBls /mnt\fR -\&./ RedHat/ doc/ ls-lR rr_moved/ -\&../ TRANS.TBL dosutils/ ls-lR.gz sbin@ -\&.buildlog bin@ etc@ misc/ tmp/ -COPYING boot/ images/ mnt/ usr@ -README boot.cat* kernels/ modules/ -RPM-PGP-KEY dev@ lib@ proc/ -.fi -.in -2 -.sp - -.sp -.LP -Solaris can mount the CD-ROM image, and understand the filenames. The image was -created properly, and you can now create the \fBCD-ROM\fR with confidence. - -.sp -.LP -As a final step, unmount and detach the images: - -.sp -.in +2 -.nf -# \fBumount /mnt\fR -# \fBlofiadm -d /dev/lofi/1\fR -# \fBlofiadm\fR -Block Device File Options -.fi -.in -2 -.sp - -.LP -\fBExample 2 \fRMounting a Floppy Image -.sp -.LP -This is similar to the first example. - -.sp -.LP -Using \fBlofi\fR to help you mount files that contain floppy images is helpful -if a floppy disk contains a file that you need, but the machine which you are -on does not have a floppy drive. It is also helpful if you do not want to take -the time to use the \fBdd\fR command to copy the image to a floppy. - -.sp -.LP -This is an example of getting to \fBMDB\fR floppy for Solaris on an x86 -platform: - -.sp -.in +2 -.nf -# \fBlofiadm -a /export/s28/MDB_s28x_wos/latest/boot.3\fR -/dev/lofi/1 -# \fBmount -F pcfs /dev/lofi/1 /mnt\fR -# \fBls /mnt\fR -\&./ COMMENT.BAT* RC.D/ SOLARIS.MAP* -\&../ IDENT* REPLACE.BAT* X/ -APPEND.BAT* MAKEDIR.BAT* SOLARIS/ -# \fBumount /mnt\fR -# \fBlofiadm -d /export/s28/MDB_s28x_wos/latest/boot.3\fR -.fi -.in -2 -.sp - -.LP -\fBExample 3 \fRMaking a \fBUFS\fR Filesystem on a File -.sp -.LP -Making a \fBUFS\fR filesystem on a file can be useful, particularly if a test -suite requires a scratch filesystem. It can be painful (or annoying) to have to -repartition a disk just for the test suite, but you do not have to. You can -\fBnewfs\fR a file with \fBlofi\fR - -.sp -.LP -Create the file: - -.sp -.in +2 -.nf -# \fBmkfile 35m /export/home/test\fR -.fi -.in -2 -.sp - -.sp -.LP -Attach it to a block device. You also get the character device that \fBnewfs\fR -requires, so \fBnewfs\fR that: - -.sp -.in +2 -.nf -# \fBlofiadm -a /export/home/test\fR -/dev/lofi/1 -# \fBnewfs /dev/rlofi/1\fR -newfs: construct a new file system /dev/rlofi/1: (y/n)? \fBy\fR -/dev/rlofi/1: 71638 sectors in 119 cylinders of 1 tracks, 602 sectors - 35.0MB in 8 cyl groups (16 c/g, 4.70MB/g, 2240 i/g) -super-block backups (for fsck -F ufs -o b=#) at: - 32, 9664, 19296, 28928, 38560, 48192, 57824, 67456, -.fi -.in -2 -.sp - -.sp -.LP -Note that \fBufs\fR might not be able to use the entire file. Mount and use the -filesystem: - -.sp -.in +2 -.nf -# \fBmount /dev/lofi/1 /mnt\fR -# \fBdf -k /mnt\fR -Filesystem kbytes used avail capacity Mounted on -/dev/lofi/1 33455 9 30101 1% /mnt -# \fBls /mnt\fR -\&./ ../ lost+found/ -# \fBumount /mnt\fR -# \fBlofiadm -d /dev/lofi/1\fR -.fi -.in -2 -.sp - -.LP -\fBExample 4 \fRCreating a PC (FAT) File System on a Unix File -.sp -.LP -The following series of commands creates a \fBFAT\fR file system on a Unix -file. The file is associated with a block device created by \fBlofiadm\fR. - -.sp -.in +2 -.nf -# \fBmkfile 10M /export/test/testfs\fR -# \fBlofiadm -a /export/test testfs\fR -/dev/lofi/1 -\fBNote use of\fR rlofi\fB, not\fR lofi\fB, in following command.\fR -# \fBmkfs -F pcfs -o nofdisk,size=20480 /dev/rlofi/1\fR -\fBConstruct a new FAT file system on /dev/rlofi/1: (y/n)?\fR y -# \fBmount -F pcfs /dev/lofi/1 /mnt\fR -# \fBcd /mnt\fR -# \fBdf -k .\fR -Filesystem kbytes used avail capacity Mounted on -/dev/lofi/1 10142 0 10142 0% /mnt -.fi -.in -2 -.sp - -.LP -\fBExample 5 \fRCompressing an Existing CD-ROM Image -.sp -.LP -The following example illustrates compressing an existing CD-ROM image -(\fBsolaris.iso\fR), verifying that the image is compressed, and then -uncompressing it. - -.sp -.in +2 -.nf -# \fBlofiadm -C gzip /export/home/solaris.iso\fR -.fi -.in -2 -.sp - -.sp -.LP -Use \fBlofiadm\fR to attach a block device to it: - -.sp -.in +2 -.nf -# \fBlofiadm -a /export/home/solaris.iso\fR - /dev/lofi/1 -.fi -.in -2 -.sp - -.sp -.LP -Check if the mapped image is compressed: - -.sp -.in +2 -.nf -# \fBlofiadm\fR -Block Device File Options -/dev/lofi/1 /export/home/solaris.iso Compressed(gzip) -/dev/lofi/2 /export/home/regular.iso - -.fi -.in -2 -.sp - -.sp -.LP -Unmap the compressed image and uncompress it: - -.sp -.in +2 -.nf -# \fBlofiadm -d /dev/lofi/1\fR -# \fBlofiadm -U /export/home/solaris.iso\fR -.fi -.in -2 -.sp - -.LP -\fBExample 6 \fRCreating an Encrypted UFS File System on a File -.sp -.LP -This example is similar to the example of making a UFS filesystem on a file, -above. - -.sp -.LP -Create the file: - -.sp -.in +2 -.nf -# \fBmkfile 35m /export/home/test\fR -.fi -.in -2 -.sp - -.sp -.LP -Attach the file to a block device and specify that the file image is encrypted. -As a result of this command, you obtain the character device, which is -subsequently used by \fBnewfs\fR: - -.sp -.in +2 -.nf -# \fBlofiadm -c aes-256-cbc -a /export/home/secrets\fR -Enter passphrase: \fBMy-M0th3r;l0v3s_m3+4lw4ys!\fR (\fBnot echoed\fR) -Re-enter passphrase: \fBMy-M0th3r;l0v3s_m3+4lw4ys!\fR (\fBnot echoed\fR) -/dev/lofi/1 - -# \fBnewfs /dev/rlofi/1\fR -newfs: construct a new file system /dev/rlofi/1: (y/n)? \fBy\fR -/dev/rlofi/1: 71638 sectors in 119 cylinders of 1 tracks, 602 sectors - 35.0MB in 8 cyl groups (16 c/g, 4.70MB/g, 2240 i/g) -super-block backups (for fsck -F ufs -o b=#) at: -32, 9664, 19296, 28928, 38560, 48192, 57824, 67456, -.fi -.in -2 -.sp - -.sp -.LP -The mapped file system shows that encryption is enabled: - -.sp -.in +2 -.nf -# \fBlofiadm\fR -Block Device File Options -/dev/lofi/1 /export/home/secrets Encrypted -.fi -.in -2 -.sp - -.sp -.LP -Mount and use the filesystem: - -.sp -.in +2 -.nf -# \fBmount /dev/lofi/1 /mnt\fR -# \fBcp moms_secret_*_recipe /mnt\fR -# \fBls /mnt\fR -\&./ moms_secret_cookie_recipe moms_secret_soup_recipe -\&../ moms_secret_fudge_recipe moms_secret_stuffing_recipe -lost+found/ moms_secret_meatloaf_recipe moms_secret_waffle_recipe -# \fBumount /mnt\fR -# \fBlofiadm -d /dev/lofi/1\fR -.fi -.in -2 -.sp - -.sp -.LP -Subsequent attempts to map the filesystem with the wrong key or the wrong -encryption algorithm will fail: - -.sp -.in +2 -.nf -# \fBlofiadm -c blowfish-cbc -a /export/home/secrets\fR -Enter passphrase: \fBmommy\fR (\fInot echoed\fR) -Re-enter passphrase: \fBmommy\fR (\fInot echoed\fR) -lofiadm: could not map file /root/lofi: Invalid argument -# \fBlofiadm\fR -Block Device File Options -# -.fi -.in -2 -.sp - -.sp -.LP -Attempts to map the filesystem without encryption will succeed, however -attempts to mount and use the filesystem will fail: - -.sp -.in +2 -.nf -# \fBlofiadm -a /export/home/secrets\fR -/dev/lofi/1 -# \fBlofiadm\fR -Block Device File Options -/dev/lofi/1 /export/home/secrets - -# \fBmount /dev/lofi/1 /mnt\fR -mount: /dev/lofi/1 is not this fstype -# -.fi -.in -2 -.sp - -.SH ENVIRONMENT VARIABLES -.sp -.LP -See \fBenviron\fR(5) for descriptions of the following environment variables -that affect the execution of \fBlofiadm\fR: \fBLC_CTYPE\fR, \fBLC_MESSAGES\fR -and \fBNLSPATH\fR. -.SH EXIT STATUS -.sp -.LP -The following exit values are returned: -.sp -.ne 2 -.na -\fB\fB0\fR\fR -.ad -.sp .6 -.RS 4n -Successful completion. -.RE - -.sp -.ne 2 -.na -\fB\fB>0\fR\fR -.ad -.sp .6 -.RS 4n -An error occurred. -.RE - -.SH SEE ALSO -.sp -.LP -\fBfsck\fR(1M), \fBmount\fR(1M), \fBmount_ufs\fR(1M), \fBnewfs\fR(1M), -\fBattributes\fR(5), \fBlofi\fR(7D), \fBlofs\fR(7FS) -.SH NOTES -.sp -.LP -Just as you would not directly access a disk device that has mounted file -systems, you should not access a file associated with a block device except -through the \fBlofi\fR file driver. It might also be appropriate to ensure that -the file has appropriate permissions to prevent such access. -.sp -.LP -The abilities of \fBlofiadm\fR, and who can use them, are controlled by the -permissions of \fB/dev/lofictl\fR. Read-access allows query operations, such as -listing all the associations. Write-access is required to do any state-changing -operations, like adding an association. As shipped, \fB/dev/lofictl\fR is owned -by \fBroot\fR, in group \fBsys\fR, and mode \fB0644\fR, so all users can do -query operations but only root can change anything. The administrator can give -users write-access, allowing them to add or delete associations, but that is -very likely a security hole and should probably only be given to a trusted -group. -.sp -.LP -When mounting a filesystem image, take care to use appropriate mount options. -In particular, the \fBnosuid\fR mount option might be appropriate for \fBUFS\fR -images whose origin is unknown. Also, some options might not be useful or -appropriate, like \fBlogging\fR or \fBforcedirectio\fR for \fBUFS\fR. For -compatibility purposes, a raw device is also exported along with the block -device. For example, \fBnewfs\fR(1M) requires one. -.sp -.LP -The output of \fBlofiadm\fR (without arguments) might change in future -releases. +'\" te +.\" Copyright 2016 Toomas Soome +.\" Copyright 2013 Nexenta Systems, Inc. All rights reserved. +.\" Copyright (c) 2008, Sun Microsystems, Inc. All Rights Reserved +.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions and limitations under the License. When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with +.\" the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] +.Dd Jun 14, 2016 +.Dt LOFIADM 1M +.Os +.Sh NAME +.Nm lofiadm +.Nd administer files available as block devices through lofi +.Sh SYNOPSIS +.Nm +.Op Fl r +.Op Fl l +.Fl a Ar file Op Ar device +.Nm +.Op Fl r +.Fl c +.Ar crypto_algorithm +.Fl a +.Ar file Op Ar device +.Nm +.Op Fl r +.Fl c Ar crypto_algorithm +.Fl k Ar raw_key_file +.Fl a Ar file Op Ar device +.Nm +.Op Fl r +.Fl c Ar crypto_algorithm +.Fl T Ar token_key +.Fl a Ar file Op Ar device +.Nm +.Op Fl r +.Fl c Ar crypto_algorithm +.Fl T Ar token_key +.Fl k Ar wrapped_key_file +.Fl a Ar file Op Ar device +.Nm +.Op Fl r +.Fl c Ar crypto_algorithm +.Fl e +.Fl a Ar file Op Ar device +.Nm +.Fl C Ar algorithm +.Op Fl s Ar segment_size +.Ar file +.Nm +.Fl d Ar file Ns | Ns Ar device +.Nm +.Fl U Ar file +.Nm +.Op Ar file Ns | Ns device +.Sh DESCRIPTION +.Nm +administers +.Sy lofi , +the loopback file driver. +.Sy lofi +allows a file to be associated with a block device. That file can then be +accessed through the block device. This is useful when the file contains an +image of some filesystem (such as a floppy or +.Sy CD-ROM +image), because the block device can then be used with the normal system +utilities for mounting, checking or repairing filesystems. See +.Xr fsck 1M +and +.Xr mount 1M . +.Pp +Use +.Nm +to add a file as a loopback device, remove such an +association, or print information about the current associations. +.Pp +Encryption and compression options are mutually exclusive on the command line. +Further, an encrypted file cannot be compressed later, nor can a compressed +file be encrypted later. +.Pp +In the global zone, +.Nm +can be used on both the global +zone devices and all devices owned by other non-global zones on the system. +.Ss Labeled Devices +If the command line flag, +.Fl l , +is used while creating a loopack device, +.Sy lofi +will create a labeled loopback +device, and will generate device links in +.Pa /dev/{dsk,rdsk} +directories for partitions or slices. +.Pp +Before using these devices, users should create or verify +partitioning by using partition management tools such as +.Xr format 1M and +.Xr fdisk 1M . +Once the device has been appropriately partitioned, the labeled +device can be used as normal disk to create and mount file systems and to store +data. Mappings created by +.Nm +are not permanent and not persisted by the system. If power is lost or the system +is rebooted, then the mappings will need to be created again. +.Pp +The partition table requires space from the mapped file. +.Sy lofi +does not support converting previously created unlabeled loopback device images +to labeled loopback devices. If an unlabeled device is used as a labeled device, +writing to it will corrupt it. +.Sh OPTIONS +The following options are supported: +.Bl -tag -width Ds +.It Fl a Ar file Op Ar device +Add +.Sy file +as a block device. +.Pp +If +.Sy device +is not specified, an available device is picked. +.Pp +If +.Sy device +is specified, +.Nm +attempts to assign it to +.Sy file . +.Sy device +must be available or +.Nm +will fail. The ability to specify a device is provided for use in scripts that +wish to reestablish a particular set of associations. +A device may not be specified when using a labeled lofi device. +.It Fl C Ar {gzip | gzip-N | lzma} +Compress the file with the specified compression algorithm. +.Pp +The +.Sy gzip +compression algorithm uses the same compression as the open-source +.Sy gzip +command. You can specify the +.Sy gzip +level by using the value gzip-\fR\fIN\fR where \fIN\fR is 6 (fast) or 9 +(best compression ratio). Currently, +.Sy gzip , +without a number, is equivalent to +.Sy gzip-6 +(which is also the default for the +.Sy gzip +command). +.Pp +.Sy lzma +stands for the LZMA (Lempel-Ziv-Markov) compression algorithm. +.Pp +Note that you cannot write to a compressed file, nor can you mount a compressed +file read/write. +.It Fl d Ar file Ns | Ns Ar device +Remove an association by +.Sy file +or +.Sy device +name, if the associated block device is not busy, and deallocates the block +device. +.It Fl l +This option should be used with +.Fl a +option to create labeled loopback device. If created in local zone, the device +has to be enabled in zone configuration. +.It Fl r +If the +.Fl r +option is specified before the +.Fl a +option, the +.Sy device +will be opened read-only. +.It Fl s Ar segment_size +The segment size to use to divide the file being compressed. +.Sy segment_size +can be an integer multiple of 512. +.It Fl U Ar file +Uncompress a compressed file. +.El +.Pp +The following options are used when the file is encrypted: +.Bl -tag -width Ds +.It Fl c Ar crypto_algorithm +Select the encryption algorithm. The algorithm must be specified when +encryption is enabled because the algorithm is not stored in the disk image. +.Pp +If none of +.Fl e , +.Fl k , +or +.Fl T +is specified, +.Nm +prompts for a passphrase, with a minimum length of eight characters, to be +entered. +The passphrase is used to derive a symmetric encryption key using PKCS#5 PBKD2. +.It Fl k Ar raw_key_file | Ar wrapped_key_file +Path to raw or wrapped symmetric encryption key. If a PKCS#11 object is also +given with the +.Fl T +option, then the key is wrapped by that object. If +.Fl T +is not specified, the key is used raw. +.It Fl T Ar token_key +The key in a PKCS#11 token to use for the encryption or for unwrapping the key +file. +.Pp +If +.Fl k +is also specified, +.Fl T +identifies the unwrapping key, which must be an RSA private key. +.It Fl e +Generate an ephemeral symmetric encryption key. +.El +.Sh OPERANDS +The following operands are supported: +.Bl -tag -width Ds +.It Ar crypto_algorithm +One of: +.Sy aes-128-cbc , +.Sy aes-192-cbc , +.Sy aes-256-cbc , +.Sy des3-cbc , +.Sy blowfish-cbc . +.It Ar device +Display the file name associated with the block device +.Sy device . +.Pp +Without arguments, print a list of the current associations. Filenames must be +valid absolute pathnames. +.Pp +When a file is added, it is opened for reading or writing by root. Any +restrictions apply (such as restricted root access over +.Sy NFS Ns ). +The file is held open until the association is removed. It is not actually +accessed until the block device is used, so it will never be written to if the +block device is only opened read-only. +.Pp +Note that the filename may appear as "?" if it is not possible to resolve the +path in the current context (for example, if it's an NFS path in a non-global +zone). +.It Ar file +Display the block device associated with +.Sy file . +.It Ar raw_key_file +Path to a file of the appropriate length, in bits, to use as a raw symmetric +encryption key. +.It Ar token_key +PKCS#11 token object in the format: +.Pp +.Ar token_name Ns : Ns Ar manufacturer_id Ns : Ns Ar serial_number Ns : Ns Ar key_label +.Pp +All but the key label are optional and can be empty. For example, to specify a +token object with only its key label +.Sy MylofiKey , +use: +.Pp +.Fl T Ar ::: Ns Ar MylofiKey +.It Ar wrapped_key_file +Path to file containing a symmetric encryption key wrapped by the RSA private +key specified by +.Fl T . +.El +.Sh ENVIRONMENT +See +.Xr environ 5 +for descriptions of the following environment variables +that affect the execution of +.Nm +: +.Sy LC_CTYPE , +.Sy LC_MESSAGES +and +.Sy NLSPATH . +.Sh EXIT STATUS +The following exit values are returned: +.Bl -tag -width Ds +.It Sy 0 +Successful completion. +.It Sy >0 +An error occurred. +.El +.Sh EXAMPLES +.Bl -tag -width Ds +.It Sy Example 1 No Mounting an Existing CD-ROM Image +You should ensure that Solaris understands the image before creating the +.Sy CD . +.Sy lofi +allows you to mount the image and see if it works. +.Pp +This example mounts an existing +.Sy CD-ROM +image +.Pf ( Sy sparc.iso Ns ), +of the +.Sy Red Hat 6.0 CD +which was downloaded from the Internet. It was created +with the +.Sy mkisofs +utility from the Internet. +.Pp +Use +.Nm +to attach a block device to it: +.Bd -literal +# lofiadm -a /home/mike_s/RH6.0/sparc.iso +/dev/lofi/1 +.Ed +.Pp +.Nm +picks the device and prints the device name to the standard +output. You can run +.Nm +again by issuing the following command: +.Bd -literal +# lofiadm +Block Device File Options +/dev/lofi/1 /home/mike_s/RH6.0/sparc.iso - +.Ed +.Pp +Or, you can give it one name and ask for the other, by issuing the following +command: +.Bd -literal +# lofiadm /dev/lofi/1 +/home/mike_s/RH6.0/sparc.iso +.Ed +.Pp +Use the +.Xr mount 1M +command to mount the image: +.Bd -literal +# mount -F hsfs -o ro /dev/lofi/1 /mnt +.Ed +.Pp +Check to ensure that Solaris understands the image: +.Bd -literal +# df -k /mnt +Filesystem kbytes used avail capacity Mounted on +/dev/lofi/1 512418 512418 0 100% /mnt +# ls /mnt +\&./ RedHat/ doc/ ls-lR rr_moved/ +\&../ TRANS.TBL dosutils/ ls-lR.gz sbin@ +\&.buildlog bin@ etc@ misc/ tmp/ +COPYING boot/ images/ mnt/ usr@ +README boot.cat* kernels/ modules/ +RPM-PGP-KEY dev@ lib@ proc/ +.Ed +.Pp +Solaris can mount the CD-ROM image, and understand the filenames. The image was +created properly, and you can now create the +.Sy CD-ROM +with confidence. +.Pp +As a final step, unmount and detach the images: +.Bd -literal +# umount /mnt +# lofiadm -d /dev/lofi/1 +# lofiadm +Block Device File Options +.Ed +.It Sy Example 2 No Mounting a Floppy Image +This is similar to the first example. +.Pp +Using +.Sy lofi +to help you mount files that contain floppy images is helpful +if a floppy disk contains a file that you need, but the machine which you are +on does not have a floppy drive. It is also helpful if you do not want to take +the time to use the +.Sy dd +command to copy the image to a floppy. +.Pp +This is an example of getting to +.Sy MDB +floppy for Solaris on an x86 platform: +.Bd -literal +# lofiadm -a /export/s28/MDB_s28x_wos/latest/boot.3 +/dev/lofi/1 +# mount -F pcfs /dev/lofi/1 /mnt +# ls /mnt +\&./ COMMENT.BAT* RC.D/ SOLARIS.MAP* +\&../ IDENT* REPLACE.BAT* X/ +APPEND.BAT* MAKEDIR.BAT* SOLARIS/ +# umount /mnt +# lofiadm -d /export/s28/MDB_s28x_wos/latest/boot.3 +.Ed +.It Sy Example 3 No Making a Sy UFS No Filesystem on a File +Making a +.Sy UFS +filesystem on a file can be useful, particularly if a test +suite requires a scratch filesystem. It can be painful (or annoying) to have to +repartition a disk just for the test suite, but you do not have to. You can +.Sy newfs +a file with +.Sy lofi . +.Pp +Create the file: +.Bd -literal +# mkfile 35m /export/home/test +.Ed +.Pp +Attach it to a block device. You also get the character device that +.Sy newfs +requires, so +.Sy newfs +that: +.Bd -literal +# lofiadm -a /export/home/test +/dev/lofi/1 +# newfs /dev/rlofi/1 +newfs: construct a new file system /dev/rlofi/1: (y/n)? y +/dev/rlofi/1: 71638 sectors in 119 cylinders of 1 tracks, 602 sectors + 35.0MB in 8 cyl groups (16 c/g, 4.70MB/g, 2240 i/g) +super-block backups (for fsck -F ufs -o b=#) at: + 32, 9664, 19296, 28928, 38560, 48192, 57824, 67456, +.Ed +.Pp +Note that +.Sy ufs +might not be able to use the entire file. Mount and use the filesystem: +.Bd -literal +# mount /dev/lofi/1 /mnt +# df -k /mnt +Filesystem kbytes used avail capacity Mounted on +/dev/lofi/1 33455 9 30101 1% /mnt +# ls /mnt +\&./ ../ lost+found/ +# umount /mnt +# lofiadm -d /dev/lofi/1 +.Ed +.It Sy Example 4 No Creating a PC (FAT) File System on a Unix File +The following series of commands creates a +.Sy FAT +file system on a Unix file. The file is associated with a block device created by +.Nm +. +.Bd -literal +# mkfile 10M /export/test/testfs +# lofiadm -a /export/test testfs +/dev/lofi/1 +.Ed +.Pp +Note use of +.Sy rlofi , +not +.Sy lofi , +in following command. +.Bd -literal +# mkfs -F pcfs -o nofdisk,size=20480 /dev/rlofi/1 +Construct a new FAT file system on /dev/rlofi/1: (y/n)? y +# mount -F pcfs /dev/lofi/1 /mnt +# cd /mnt +# df -k . +Filesystem kbytes used avail capacity Mounted on +/dev/lofi/1 10142 0 10142 0% /mnt +.Ed +.It Sy Example 5 No Compressing an Existing CD-ROM Image +The following example illustrates compressing an existing CD-ROM image +.Pf ( Sy solaris.iso Ns ), +verifying that the image is compressed, and then uncompressing it. +.Bd -literal +# lofiadm -C gzip /export/home/solaris.iso +.Ed +.Pp +Use +.Nm +to attach a block device to it: +.Bd -literal +# lofiadm -a /export/home/solaris.iso + /dev/lofi/1 +.Ed +.Pp +Check if the mapped image is compressed: +.Bd -literal +# lofiadm +Block Device File Options +/dev/lofi/1 /export/home/solaris.iso Compressed(gzip) +/dev/lofi/2 /export/home/regular.iso - +.Ed +.Pp +Unmap the compressed image and uncompress it: +.Bd -literal +# lofiadm -d /dev/lofi/1 +# lofiadm -U /export/home/solaris.iso +.Ed +.It Sy Example 6 No Creating an Encrypted UFS File System on a File +This example is similar to the example of making a UFS filesystem on a file, +above. +.Pp +Create the file: +.Bd -literal +# mkfile 35m /export/home/test +.Ed +.Pp +Attach the file to a block device and specify that the file image is encrypted. +As a result of this command, you obtain the character device, which is +subsequently used by +.Sy newfs : +.Bd -literal +# lofiadm -c aes-256-cbc -a /export/home/secrets +Enter passphrase: My-M0th3r;l0v3s_m3+4lw4ys! (not echoed) +Re-enter passphrase: My-M0th3r;l0v3s_m3+4lw4ys! (not echoed) +/dev/lofi/1 + +# newfs /dev/rlofi/1 +newfs: construct a new file system /dev/rlofi/1: (y/n)? y +/dev/rlofi/1: 71638 sectors in 119 cylinders of 1 tracks, 602 sectors + 35.0MB in 8 cyl groups (16 c/g, 4.70MB/g, 2240 i/g) +super-block backups (for fsck -F ufs -o b=#) at: +32, 9664, 19296, 28928, 38560, 48192, 57824, 67456, +.Ed +.Pp +The mapped file system shows that encryption is enabled: +.Bd -literal +# lofiadm +Block Device File Options +/dev/lofi/1 /export/home/secrets Encrypted +.Ed +.Pp +Mount and use the filesystem: +.Bd -literal +# mount /dev/lofi/1 /mnt +# cp moms_secret_*_recipe /mnt +# ls /mnt +\&./ moms_secret_cookie_recipe moms_secret_soup_recipe +\&../ moms_secret_fudge_recipe moms_secret_stuffing_recipe +lost+found/ moms_secret_meatloaf_recipe moms_secret_waffle_recipe +# umount /mnt +# lofiadm -d /dev/lofi/1 +.Ed +.Pp +Subsequent attempts to map the filesystem with the wrong key or the wrong +encryption algorithm will fail: +.Bd -literal +# lofiadm -c blowfish-cbc -a /export/home/secrets\fR +Enter passphrase: mommy (not echoed) +Re-enter passphrase: mommy (not echoed) +lofiadm: could not map file /root/lofi: Invalid argument +# lofiadm +Block Device File Options +# +.Ed +.Pp +Attempts to map the filesystem without encryption will succeed, however +attempts to mount and use the filesystem will fail: +.Bd -literal +# lofiadm -a /export/home/secrets +/dev/lofi/1 +# lofiadm +Block Device File Options +/dev/lofi/1 /export/home/secrets - +# mount /dev/lofi/1 /mnt +mount: /dev/lofi/1 is not this fstype +# +.Ed +.El +.Sh SEE ALSO +.Xr fdisk 1M , +.Xr format 1M , +.Xr fsck 1M , +.Xr mount 1M , +.Xr mount_ufs 1M , +.Xr newfs 1M , +.Xr attributes 5 , +.Xr lofi 7D , +.Xr lofs 7FS +.Sh NOTES +Just as you would not directly access a disk device that has mounted file +systems, you should not access a file associated with a block device except +through the +.Sy lofi +file driver. It might also be appropriate to ensure that +the file has appropriate permissions to prevent such access. +.Pp +The abilities of +.Nm +, and who can use them, are controlled by the +permissions of +.Pa /dev/lofictl . +Read-access allows query operations, such as +listing all the associations. Write-access is required to do any state-changing +operations, like adding an association. As shipped, +.Pa /dev/lofictl +is owned by +.Sy root , +in group +.Sy sys , +and mode +.Sy 0644 , +so all users can do query operations but only root can change anything. +The administrator can give users write-access, allowing them to add or +delete associations, but that is very likely a security hole and should +probably only be given to a trusted group. +.Pp +When mounting a filesystem image, take care to use appropriate mount options. +In particular, the +.Sy nosuid +mount option might be appropriate for +.Sy UFS +images whose origin is unknown. Also, some options might not be useful or +appropriate, like +.Sy logging +or +.Sy forcedirectio +for +.Sy UFS . +For compatibility purposes, a raw device is also exported along with the block +device. For example, +.Xr newfs 1M +requires one. +.Pp +The output of +.Nm +(without arguments) might change in future releases. diff --git a/usr/src/uts/common/fs/vfs.c b/usr/src/uts/common/fs/vfs.c index e179d934ed..64ed4386a4 100644 --- a/usr/src/uts/common/fs/vfs.c +++ b/usr/src/uts/common/fs/vfs.c @@ -22,6 +22,7 @@ * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Joyent, Inc. All rights reserved. * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2016 Toomas Soome */ /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ @@ -355,8 +356,8 @@ fs_copyfsops(const fs_operation_def_t *template, vfsops_t *actual, } void -zfs_boot_init() { - +zfs_boot_init(void) +{ if (strcmp(rootfs.bo_fstype, MNTTYPE_ZFS) == 0) spa_boot_init(); } @@ -525,7 +526,7 @@ vfs_init(vfs_t *vfsp, vfsops_t *op, void *data) vfsp->vfs_prev = vfsp; vfsp->vfs_zone_next = vfsp; vfsp->vfs_zone_prev = vfsp; - vfsp->vfs_lofi_minor = 0; + vfsp->vfs_lofi_id = 0; sema_init(&vfsp->vfs_reflock, 1, NULL, SEMA_DEFAULT, NULL); vfsimpl_setup(vfsp); vfsp->vfs_data = (data); @@ -984,7 +985,7 @@ lofi_add(const char *fsname, struct vfs *vfsp, ldi_ident_t ldi_id; ldi_handle_t ldi_hdl; vfssw_t *vfssw; - int minor; + int id; int err = 0; if ((vfssw = vfs_getvfssw(fsname)) == NULL) @@ -1028,12 +1029,12 @@ lofi_add(const char *fsname, struct vfs *vfsp, goto out2; err = ldi_ioctl(ldi_hdl, LOFI_MAP_FILE, (intptr_t)li, - FREAD | FWRITE | FKIOCTL, kcred, &minor); + FREAD | FWRITE | FKIOCTL, kcred, &id); (void) ldi_close(ldi_hdl, FREAD | FWRITE, kcred); if (!err) - vfsp->vfs_lofi_minor = minor; + vfsp->vfs_lofi_id = id; out2: ldi_ident_release(ldi_id); @@ -1054,13 +1055,13 @@ lofi_remove(struct vfs *vfsp) ldi_handle_t ldi_hdl; int err; - if (vfsp->vfs_lofi_minor == 0) + if (vfsp->vfs_lofi_id == 0) return; ldi_id = ldi_ident_from_anon(); li = kmem_zalloc(sizeof (*li), KM_SLEEP); - li->li_minor = vfsp->vfs_lofi_minor; + li->li_id = vfsp->vfs_lofi_id; li->li_cleanup = B_TRUE; err = ldi_open_by_name("/dev/lofictl", FREAD | FWRITE, kcred, @@ -1075,7 +1076,7 @@ lofi_remove(struct vfs *vfsp) (void) ldi_close(ldi_hdl, FREAD | FWRITE, kcred); if (!err) - vfsp->vfs_lofi_minor = 0; + vfsp->vfs_lofi_id = 0; out: ldi_ident_release(ldi_id); @@ -1105,7 +1106,7 @@ out: */ int domount(char *fsname, struct mounta *uap, vnode_t *vp, struct cred *credp, - struct vfs **vfspp) + struct vfs **vfspp) { struct vfssw *vswp; vfsops_t *vfsops; @@ -1481,7 +1482,7 @@ domount(char *fsname, struct mounta *uap, vnode_t *vp, struct cred *credp, /* * PRIV_SYS_MOUNT doesn't mean you can become root. */ - if (vfsp->vfs_lofi_minor != 0) { + if (vfsp->vfs_lofi_id != 0) { uap->flags |= MS_NOSUID; vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL, 0, 0); } @@ -2788,7 +2789,7 @@ vfs_freeopttbl(mntopts_t *mp) /* ARGSUSED */ static int vfs_mntdummyread(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cred, - caller_context_t *ct) + caller_context_t *ct) { return (0); } @@ -2796,7 +2797,7 @@ vfs_mntdummyread(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cred, /* ARGSUSED */ static int vfs_mntdummywrite(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cred, - caller_context_t *ct) + caller_context_t *ct) { return (0); } @@ -4800,14 +4801,14 @@ vfs_get_lofi(vfs_t *vfsp, vnode_t **vpp) int strsize; int err; - if (vfsp->vfs_lofi_minor == 0) { + if (vfsp->vfs_lofi_id == 0) { *vpp = NULL; return (-1); } - strsize = snprintf(NULL, 0, LOFINODE_PATH, vfsp->vfs_lofi_minor); + strsize = snprintf(NULL, 0, LOFINODE_PATH, vfsp->vfs_lofi_id); path = kmem_alloc(strsize + 1, KM_SLEEP); - (void) snprintf(path, strsize + 1, LOFINODE_PATH, vfsp->vfs_lofi_minor); + (void) snprintf(path, strsize + 1, LOFINODE_PATH, vfsp->vfs_lofi_id); /* * We may be inside a zone, so we need to use the /dev path, but diff --git a/usr/src/uts/common/io/cmlb.c b/usr/src/uts/common/io/cmlb.c index f668380868..ea04806be9 100644 --- a/usr/src/uts/common/io/cmlb.c +++ b/usr/src/uts/common/io/cmlb.c @@ -23,6 +23,7 @@ * Copyright 2012 DEY Storage Systems, Inc. All rights reserved. * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2016 Toomas Soome */ /* @@ -647,6 +648,9 @@ cmlb_free_handle(cmlb_handle_t *cmlbhandlep) * If there is a valid Solaris partition, s0 and s2 will * only cover the entire Solaris partition. * + * CMLB_CREATE_P0_MINOR_NODE: create p0 node covering + * the entire disk. Used by lofi to ensure presence of + * whole disk device node in case of LOFI_MAP_FILE ioctl. * * cmlbhandle cmlb handle associated with device * @@ -1057,14 +1061,9 @@ cmlb_partinfo(cmlb_handle_t cmlbhandle, int part, diskaddr_t *nblocksp, (void) cmlb_validate_geometry((struct cmlb_lun *)cl, B_FALSE, 0, tg_cookie); -#if defined(_SUNOS_VTOC_16) if (((!cl->cl_f_geometry_is_valid) || (part < NDKMAP && cl->cl_solaris_size == 0)) && (part != P0_RAW_DISK)) { -#else - if ((!cl->cl_f_geometry_is_valid) || - (part < NDKMAP && cl->cl_solaris_size == 0)) { -#endif rval = EINVAL; } else { if (startblockp != NULL) @@ -1361,8 +1360,14 @@ cmlb_ioctl(cmlb_handle_t cmlbhandle, dev_t dev, int cmd, intptr_t arg, dev_t cmlb_make_device(struct cmlb_lun *cl) { - return (makedevice(ddi_driver_major(CMLB_DEVINFO(cl)), - ddi_get_instance(CMLB_DEVINFO(cl)) << CMLBUNIT_SHIFT)); + if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE) { + return (makedevice(ddi_driver_major(CMLB_DEVINFO(cl)), + ddi_get_instance( + CMLB_DEVINFO(cl)) << CMLBUNIT_FORCE_P0_SHIFT)); + } else { + return (makedevice(ddi_driver_major(CMLB_DEVINFO(cl)), + ddi_get_instance(CMLB_DEVINFO(cl)) << CMLBUNIT_SHIFT)); + } } /* @@ -1444,7 +1449,7 @@ static int cmlb_create_minor_nodes(struct cmlb_lun *cl) { struct driver_minor_data *dmdp; - int instance; + int instance, shift; char name[48]; cmlb_label_t newlabeltype; boolean_t internal; @@ -1455,6 +1460,11 @@ cmlb_create_minor_nodes(struct cmlb_lun *cl) internal = VOID2BOOLEAN( (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0); + if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE) + shift = CMLBUNIT_FORCE_P0_SHIFT; + else + shift = CMLBUNIT_SHIFT; + /* check the most common case */ if (cl->cl_cur_labeltype != CMLB_LABEL_UNDEF && cl->cl_last_labeltype == cl->cl_cur_labeltype) { @@ -1482,7 +1492,7 @@ cmlb_create_minor_nodes(struct cmlb_lun *cl) if (cmlb_create_minor(CMLB_DEVINFO(cl), name, dmdp->type, - (instance << CMLBUNIT_SHIFT) | dmdp->minor, + (instance << shift) | dmdp->minor, cl->cl_node_type, NULL, internal) == DDI_FAILURE) { /* * Clean up any nodes that may have been @@ -1495,6 +1505,27 @@ cmlb_create_minor_nodes(struct cmlb_lun *cl) dmdp++; } cl->cl_last_labeltype = newlabeltype; +#if defined(_SUNOS_VTOC_8) + /* + * "emulate" p0 device for sparc, used by lofi + */ + if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE) { + if (cmlb_create_minor(CMLB_DEVINFO(cl), "q", S_IFBLK, + (instance << CMLBUNIT_FORCE_P0_SHIFT) | P0_RAW_DISK, + cl->cl_node_type, NULL, internal) == DDI_FAILURE) { + ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL); + return (ENXIO); + } + + if (cmlb_create_minor(CMLB_DEVINFO(cl), "q,raw", + S_IFCHR, + (instance << CMLBUNIT_FORCE_P0_SHIFT) | P0_RAW_DISK, + cl->cl_node_type, NULL, internal) == DDI_FAILURE) { + ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL); + return (ENXIO); + } + } +#endif /* defined(_SUNOS_VTOC_8) */ return (0); } @@ -1536,20 +1567,20 @@ cmlb_create_minor_nodes(struct cmlb_lun *cl) ddi_remove_minor_node(CMLB_DEVINFO(cl), "h"); ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw"); (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd", - S_IFBLK, (instance << CMLBUNIT_SHIFT) | WD_NODE, + S_IFBLK, (instance << shift) | WD_NODE, cl->cl_node_type, NULL, internal); (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd,raw", - S_IFCHR, (instance << CMLBUNIT_SHIFT) | WD_NODE, + S_IFCHR, (instance << shift) | WD_NODE, cl->cl_node_type, NULL, internal); } else { /* from efi to vtoc */ ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd"); ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw"); (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h", - S_IFBLK, (instance << CMLBUNIT_SHIFT) | WD_NODE, + S_IFBLK, (instance << shift) | WD_NODE, cl->cl_node_type, NULL, internal); (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw", - S_IFCHR, (instance << CMLBUNIT_SHIFT) | WD_NODE, + S_IFCHR, (instance << shift) | WD_NODE, cl->cl_node_type, NULL, internal); } @@ -1605,7 +1636,6 @@ cmlb_validate_geometry(struct cmlb_lun *cl, boolean_t forcerevalid, int flags, capacity = cl->cl_blockcount; -#if defined(_SUNOS_VTOC_16) /* * Set up the "whole disk" fdisk partition; this should always * exist, regardless of whether the disk contains an fdisk table @@ -1618,7 +1648,7 @@ cmlb_validate_geometry(struct cmlb_lun *cl, boolean_t forcerevalid, int flags, * so no truncation happens */ cl->cl_map[P0_RAW_DISK].dkl_nblk = capacity; -#endif + /* * Refresh the logical and physical geometry caches. * (data from MODE SENSE format/rigid disk geometry pages, @@ -2043,7 +2073,7 @@ cmlb_resync_geom_caches(struct cmlb_lun *cl, diskaddr_t capacity, static int cmlb_update_ext_minor_nodes(struct cmlb_lun *cl, int num_parts) { - int i, count; + int i, count, shift; char name[48]; int instance; struct driver_minor_data *demdp, *demdpr; @@ -2060,6 +2090,10 @@ cmlb_update_ext_minor_nodes(struct cmlb_lun *cl, int num_parts) demdp = dk_ext_minor_data; demdpr = &dk_ext_minor_data[MAX_EXT_PARTS]; + if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE) + shift = CMLBUNIT_FORCE_P0_SHIFT; + else + shift = CMLBUNIT_SHIFT; if (cl->cl_logical_drive_count) { for (i = 0; i < cl->cl_logical_drive_count; i++) { @@ -2085,7 +2119,7 @@ cmlb_update_ext_minor_nodes(struct cmlb_lun *cl, int num_parts) (void) sprintf(name, "%s", demdp->name); if (cmlb_create_minor(CMLB_DEVINFO(cl), name, demdp->type, - (instance << CMLBUNIT_SHIFT) | demdp->minor, + (instance << shift) | demdp->minor, cl->cl_node_type, NULL, internal) == DDI_FAILURE) { /* * Clean up any nodes that may have been @@ -2099,7 +2133,7 @@ cmlb_update_ext_minor_nodes(struct cmlb_lun *cl, int num_parts) (void) sprintf(name, "%s", demdpr->name); if (ddi_create_minor_node(CMLB_DEVINFO(cl), name, demdpr->type, - (instance << CMLBUNIT_SHIFT) | demdpr->minor, + (instance << shift) | demdpr->minor, cl->cl_node_type, NULL) == DDI_FAILURE) { /* * Clean up any nodes that may have been @@ -4308,12 +4342,17 @@ cmlb_dkio_set_vtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, void *tg_cookie) { struct vtoc user_vtoc; - int rval = 0; + int shift, rval = 0; boolean_t internal; internal = VOID2BOOLEAN( (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0); + if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE) + shift = CMLBUNIT_FORCE_P0_SHIFT; + else + shift = CMLBUNIT_SHIFT; + #ifdef _MULTI_DATAMODEL switch (ddi_model_convert_from(flag & FMODELS)) { case DDI_MODEL_ILP32: { @@ -4375,10 +4414,10 @@ cmlb_dkio_set_vtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw"); (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h", - S_IFBLK, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, + S_IFBLK, (CMLBUNIT(dev, shift) << shift) | WD_NODE, cl->cl_node_type, NULL, internal); (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw", - S_IFCHR, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, + S_IFCHR, (CMLBUNIT(dev, shift) << shift) | WD_NODE, cl->cl_node_type, NULL, internal); mutex_enter(CMLB_MUTEX(cl)); @@ -4404,10 +4443,14 @@ static int cmlb_dkio_set_extvtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, void *tg_cookie) { - int rval = 0; + int shift, rval = 0; struct vtoc user_vtoc; boolean_t internal; + if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE) + shift = CMLBUNIT_FORCE_P0_SHIFT; + else + shift = CMLBUNIT_SHIFT; /* * Checking callers data model does not make much sense here @@ -4459,10 +4502,10 @@ cmlb_dkio_set_extvtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw"); (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h", - S_IFBLK, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, + S_IFBLK, (CMLBUNIT(dev, shift) << shift) | WD_NODE, cl->cl_node_type, NULL, internal); (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw", - S_IFCHR, (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, + S_IFCHR, (CMLBUNIT(dev, shift) << shift) | WD_NODE, cl->cl_node_type, NULL, internal); mutex_enter(CMLB_MUTEX(cl)); @@ -4925,7 +4968,7 @@ cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, void *tg_cookie) { dk_efi_t user_efi; - int rval = 0; + int shift, rval = 0; void *buffer; diskaddr_t tgt_lba; boolean_t internal; @@ -4936,6 +4979,11 @@ cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, internal = VOID2BOOLEAN( (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0); + if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE) + shift = CMLBUNIT_FORCE_P0_SHIFT; + else + shift = CMLBUNIT_SHIFT; + user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64; if (user_efi.dki_length == 0 || @@ -4976,11 +5024,11 @@ cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag, ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw"); (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd", S_IFBLK, - (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, + (CMLBUNIT(dev, shift) << shift) | WD_NODE, cl->cl_node_type, NULL, internal); (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd,raw", S_IFCHR, - (CMLBUNIT(dev) << CMLBUNIT_SHIFT) | WD_NODE, + (CMLBUNIT(dev, shift) << shift) | WD_NODE, cl->cl_node_type, NULL, internal); } else mutex_exit(CMLB_MUTEX(cl)); @@ -5344,7 +5392,6 @@ cmlb_update_fdisk_and_vtoc(struct cmlb_lun *cl, void *tg_cookie) if (cmlb_check_update_blockcount(cl, tg_cookie) != 0) return (EINVAL); -#if defined(_SUNOS_VTOC_16) /* * Set up the "whole disk" fdisk partition; this should always * exist, regardless of whether the disk contains an fdisk table @@ -5352,7 +5399,6 @@ cmlb_update_fdisk_and_vtoc(struct cmlb_lun *cl, void *tg_cookie) */ cl->cl_map[P0_RAW_DISK].dkl_cylno = 0; cl->cl_map[P0_RAW_DISK].dkl_nblk = cl->cl_blockcount; -#endif /* defined(_SUNOS_VTOC_16) */ /* * copy the lbasize and capacity so that if they're @@ -5578,7 +5624,10 @@ cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag) */ int part; - part = CMLBPART(dev); + if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE) + part = getminor(dev) & ((1 << CMLBUNIT_FORCE_P0_SHIFT) - 1); + else + part = CMLBPART(dev); mutex_enter(CMLB_MUTEX(cl)); /* don't check cl_solaris_size for pN */ @@ -5631,7 +5680,10 @@ cmlb_dkio_extpartinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag) */ int part; - part = CMLBPART(dev); + if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE) + part = getminor(dev) & ((1 << CMLBUNIT_FORCE_P0_SHIFT) - 1); + else + part = CMLBPART(dev); mutex_enter(CMLB_MUTEX(cl)); /* don't check cl_solaris_size for pN */ diff --git a/usr/src/uts/common/io/lofi.c b/usr/src/uts/common/io/lofi.c index e11f910a91..0312a54b62 100644 --- a/usr/src/uts/common/io/lofi.c +++ b/usr/src/uts/common/io/lofi.c @@ -23,6 +23,7 @@ * * Copyright 2013 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2016 Andrey Sokolov + * Copyright 2016 Toomas Soome */ /* @@ -34,14 +35,25 @@ * mounting images of filesystems. * * lofi is controlled through /dev/lofictl - this is the only device exported - * during attach, and is minor number 0. lofiadm communicates with lofi through - * ioctls on this device. When a file is attached to lofi, block and character - * devices are exported in /dev/lofi and /dev/rlofi. Currently, these devices - * are identified by their minor number, and the minor number is also used - * as the name in /dev/lofi. If we ever decide to support virtual disks, - * we'll have to divide the minor number space to identify fdisk partitions - * and slices, and the name will then be the minor number shifted down a - * few bits. Minor devices are tracked with state structures handled with + * during attach, and is instance number 0. lofiadm communicates with lofi + * through ioctls on this device. When a file is attached to lofi, block and + * character devices are exported in /dev/lofi and /dev/rlofi. These devices + * are identified by lofi instance number, and the instance number is also used + * as the name in /dev/lofi. + * + * Virtual disks, or, labeled lofi, implements virtual disk support to + * support partition table and related tools. Such mappings will cause + * block and character devices to be exported in /dev/dsk and /dev/rdsk + * directories. + * + * To support virtual disks, the instance number space is divided to two + * parts, upper part for instance number and lower part for minor number + * space to identify partitions and slices. The virtual disk support is + * implemented by stacking cmlb module. For virtual disks, the partition + * related ioctl calls are routed to cmlb module. Compression and encryption + * is not supported for virtual disks. + * + * Mapped devices are tracked with state structures handled with * ddi_soft_state(9F) for simplicity. * * A file attached to lofi is opened when attached and not closed until @@ -131,6 +143,10 @@ #include #include #include +#include +#include /* for DTYPE_DIRECT */ +#include +#include #include #define NBLOCKS_PROP_NAME "Nblocks" @@ -151,10 +167,16 @@ return (EINVAL); \ } -static dev_info_t *lofi_dip = NULL; -static void *lofi_statep = NULL; +#define DEVFS_CHANNEL "devfsadm_event_channel" +#define LOFI_TIMEOUT 30 +static evchan_t *lofi_chan; +static kmutex_t lofi_chan_lock; +static kcondvar_t lofi_chan_cv; +static nvlist_t *lofi_devlink_cache; + +static void *lofi_statep; static kmutex_t lofi_lock; /* state lock */ -static id_space_t *lofi_minor_id; +static id_space_t *lofi_id; /* lofi ID values */ static list_t lofi_list; static zone_key_t lofi_zone_key; @@ -204,6 +226,17 @@ lofi_compress_info_t lofi_compress_table[LOFI_COMPRESS_FUNCTIONS] = { {lzma_decompress, NULL, 0, "lzma"} }; +static void lofi_strategy_task(void *); +static int lofi_tg_rdwr(dev_info_t *, uchar_t, void *, diskaddr_t, + size_t, void *); +static int lofi_tg_getinfo(dev_info_t *, int, void *, void *); + +struct cmlb_tg_ops lofi_tg_ops = { + TG_DK_OPS_VERSION_1, + lofi_tg_rdwr, + lofi_tg_getinfo +}; + /*ARGSUSED*/ static void *SzAlloc(void *p, size_t size) @@ -240,47 +273,24 @@ lofi_free_comp_cache(struct lofi_state *lsp) static int is_opened(struct lofi_state *lsp) { - ASSERT(MUTEX_HELD(&lofi_lock)); - return (lsp->ls_chr_open || lsp->ls_blk_open || lsp->ls_lyr_open_count); -} + int i; + boolean_t last = B_TRUE; -static int -mark_opened(struct lofi_state *lsp, int otyp) -{ ASSERT(MUTEX_HELD(&lofi_lock)); - switch (otyp) { - case OTYP_CHR: - lsp->ls_chr_open = 1; - break; - case OTYP_BLK: - lsp->ls_blk_open = 1; - break; - case OTYP_LYR: - lsp->ls_lyr_open_count++; - break; - default: - return (-1); + for (i = 0; i < LOFI_PART_MAX; i++) { + if (lsp->ls_open_lyr[i]) { + last = B_FALSE; + break; + } } - return (0); -} -static void -mark_closed(struct lofi_state *lsp, int otyp) -{ - ASSERT(MUTEX_HELD(&lofi_lock)); - switch (otyp) { - case OTYP_CHR: - lsp->ls_chr_open = 0; - break; - case OTYP_BLK: - lsp->ls_blk_open = 0; - break; - case OTYP_LYR: - lsp->ls_lyr_open_count--; - break; - default: - break; + for (i = 0; last && (i < OTYP_LYR); i++) { + if (lsp->ls_open_reg[i]) { + last = B_FALSE; + } } + + return (!last); } static void @@ -320,10 +330,171 @@ lofi_free_crypto(struct lofi_state *lsp) } } +/* ARGSUSED */ +static int +lofi_tg_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr, diskaddr_t start, + size_t length, void *tg_cookie) +{ + struct lofi_state *lsp; + buf_t *bp; + int instance; + int rv = 0; + + instance = ddi_get_instance(dip); + if (instance == 0) /* control node does not have disk */ + return (ENXIO); + + lsp = ddi_get_soft_state(lofi_statep, instance); + + if (lsp == NULL) + return (ENXIO); + + if (cmd != TG_READ && cmd != TG_WRITE) + return (EINVAL); + + /* + * Make sure the mapping is set up by checking lsp->ls_vp_ready. + */ + mutex_enter(&lsp->ls_vp_lock); + while (lsp->ls_vp_ready == B_FALSE) + cv_wait(&lsp->ls_vp_cv, &lsp->ls_vp_lock); + mutex_exit(&lsp->ls_vp_lock); + + if (P2PHASE(length, (1U << lsp->ls_lbshift)) != 0) { + /* We can only transfer whole blocks at a time! */ + return (EINVAL); + } + + bp = getrbuf(KM_SLEEP); + + if (cmd == TG_READ) { + bp->b_flags = B_READ; + } else { + if (lsp->ls_readonly == B_TRUE) { + freerbuf(bp); + return (EROFS); + } + bp->b_flags = B_WRITE; + } + + bp->b_un.b_addr = bufaddr; + bp->b_bcount = length; + bp->b_lblkno = start; + bp->b_private = NULL; + bp->b_edev = lsp->ls_dev; + + if (lsp->ls_kstat) { + mutex_enter(lsp->ls_kstat->ks_lock); + kstat_waitq_enter(KSTAT_IO_PTR(lsp->ls_kstat)); + mutex_exit(lsp->ls_kstat->ks_lock); + } + (void) taskq_dispatch(lsp->ls_taskq, lofi_strategy_task, bp, KM_SLEEP); + (void) biowait(bp); + + rv = geterror(bp); + freerbuf(bp); + return (rv); +} + +/* + * Get device geometry info for cmlb. + * + * We have mapped disk image as virtual block device and have to report + * physical/virtual geometry to cmlb. + * + * So we have two principal cases: + * 1. Uninitialised image without any existing labels, + * for this case we fabricate the data based on mapped image. + * 2. Image with existing label information. + * Since we have no information how the image was created (it may be + * dump from some physical device), we need to rely on label information + * from image, or we get "corrupted label" errors. + * NOTE: label can be MBR, MBR+SMI, GPT + */ +static int +lofi_tg_getinfo(dev_info_t *dip, int cmd, void *arg, void *tg_cookie) +{ + struct lofi_state *lsp; + int instance; + int ashift; + + _NOTE(ARGUNUSED(tg_cookie)); + instance = ddi_get_instance(dip); + if (instance == 0) /* control device has no storage */ + return (ENXIO); + + lsp = ddi_get_soft_state(lofi_statep, instance); + + if (lsp == NULL) + return (ENXIO); + + /* + * Make sure the mapping is set up by checking lsp->ls_vp_ready. + * + * When mapping is created, new lofi instance is created and + * lofi_attach() will call cmlb_attach() as part of the procedure + * to set the mapping up. This chain of events will happen in + * the same thread. + * Since cmlb_attach() will call lofi_tg_getinfo to get + * capacity, we return error on that call if cookie is set, + * otherwise lofi_attach will be stuck as the mapping is not yet + * finalized and lofi is not yet ready. + * Note, such error is not fatal for cmlb, as the label setup + * will be finalized when cmlb_validate() is called. + */ + mutex_enter(&lsp->ls_vp_lock); + if (tg_cookie != NULL && lsp->ls_vp_ready == B_FALSE) { + mutex_exit(&lsp->ls_vp_lock); + return (ENXIO); + } + while (lsp->ls_vp_ready == B_FALSE) + cv_wait(&lsp->ls_vp_cv, &lsp->ls_vp_lock); + mutex_exit(&lsp->ls_vp_lock); + + ashift = lsp->ls_lbshift; + + switch (cmd) { + case TG_GETPHYGEOM: { + cmlb_geom_t *geomp = arg; + + geomp->g_capacity = + (lsp->ls_vp_size - lsp->ls_crypto_offset) >> ashift; + geomp->g_nsect = lsp->ls_dkg.dkg_nsect; + geomp->g_nhead = lsp->ls_dkg.dkg_nhead; + geomp->g_acyl = lsp->ls_dkg.dkg_acyl; + geomp->g_ncyl = lsp->ls_dkg.dkg_ncyl; + geomp->g_secsize = (1U << ashift); + geomp->g_intrlv = lsp->ls_dkg.dkg_intrlv; + geomp->g_rpm = lsp->ls_dkg.dkg_rpm; + return (0); + } + + case TG_GETCAPACITY: + *(diskaddr_t *)arg = + (lsp->ls_vp_size - lsp->ls_crypto_offset) >> ashift; + return (0); + + case TG_GETBLOCKSIZE: + *(uint32_t *)arg = (1U << ashift); + return (0); + + case TG_GETATTR: { + tg_attribute_t *tgattr = arg; + + tgattr->media_is_writable = !lsp->ls_readonly; + tgattr->media_is_solid_state = B_FALSE; + return (0); + } + + default: + return (EINVAL); + } +} + static void lofi_destroy(struct lofi_state *lsp, cred_t *credp) { - minor_t minor = getminor(lsp->ls_dev); + int id = LOFI_MINOR2ID(getminor(lsp->ls_dev)); int i; ASSERT(MUTEX_HELD(&lofi_lock)); @@ -345,13 +516,17 @@ lofi_destroy(struct lofi_state *lsp, cred_t *credp) sizeof (struct compbuf) * lofi_taskq_nthreads); } - (void) VOP_CLOSE(lsp->ls_vp, lsp->ls_openflag, - 1, 0, credp, NULL); - VN_RELE(lsp->ls_vp); + if (lsp->ls_vp != NULL) { + (void) VOP_PUTPAGE(lsp->ls_vp, 0, 0, B_INVAL, credp, NULL); + (void) VOP_CLOSE(lsp->ls_vp, lsp->ls_openflag, + 1, 0, credp, NULL); + VN_RELE(lsp->ls_vp); + } if (lsp->ls_stacked_vp != lsp->ls_vp) VN_RELE(lsp->ls_stacked_vp); - taskq_destroy(lsp->ls_taskq); + if (lsp->ls_taskq != NULL) + taskq_destroy(lsp->ls_taskq); if (lsp->ls_kstat != NULL) kstat_delete(lsp->ls_kstat); @@ -374,28 +549,27 @@ lofi_destroy(struct lofi_state *lsp, cred_t *credp) mutex_destroy(&lsp->ls_comp_bufs_lock); mutex_destroy(&lsp->ls_kstat_lock); mutex_destroy(&lsp->ls_vp_lock); + cv_destroy(&lsp->ls_vp_cv); + lsp->ls_vp_ready = B_FALSE; - ASSERT(ddi_get_soft_state(lofi_statep, minor) == lsp); - ddi_soft_state_free(lofi_statep, minor); - id_free(lofi_minor_id, minor); + ASSERT(ddi_get_soft_state(lofi_statep, id) == lsp); + (void) ndi_devi_offline(lsp->ls_dip, NDI_DEVI_REMOVE); + id_free(lofi_id, id); } static void -lofi_free_dev(dev_t dev) +lofi_free_dev(struct lofi_state *lsp) { - minor_t minor = getminor(dev); - char namebuf[50]; - ASSERT(MUTEX_HELD(&lofi_lock)); - (void) ddi_prop_remove(dev, lofi_dip, ZONE_PROP_NAME); - (void) ddi_prop_remove(dev, lofi_dip, SIZE_PROP_NAME); - (void) ddi_prop_remove(dev, lofi_dip, NBLOCKS_PROP_NAME); - - (void) snprintf(namebuf, sizeof (namebuf), "%d", minor); - ddi_remove_minor_node(lofi_dip, namebuf); - (void) snprintf(namebuf, sizeof (namebuf), "%d,raw", minor); - ddi_remove_minor_node(lofi_dip, namebuf); + if (lsp->ls_cmlbhandle != NULL) { + cmlb_invalidate(lsp->ls_cmlbhandle, 0); + cmlb_detach(lsp->ls_cmlbhandle, 0); + cmlb_free_handle(&lsp->ls_cmlbhandle); + lsp->ls_cmlbhandle = NULL; + } + (void) ddi_prop_remove_all(lsp->ls_dip); + ddi_remove_minor_node(lsp->ls_dip, NULL); } /*ARGSUSED*/ @@ -424,7 +598,7 @@ lofi_zone_shutdown(zoneid_t zoneid, void *arg) if (is_opened(lsp)) { lsp->ls_cleanup = 1; } else { - lofi_free_dev(lsp->ls_dev); + lofi_free_dev(lsp); lofi_destroy(lsp, kcred); } } @@ -436,9 +610,20 @@ lofi_zone_shutdown(zoneid_t zoneid, void *arg) static int lofi_open(dev_t *devp, int flag, int otyp, struct cred *credp) { - minor_t minor; + int id; + minor_t part; + uint64_t mask; + diskaddr_t nblks; + diskaddr_t lba; + boolean_t ndelay; + struct lofi_state *lsp; + if (otyp >= OTYPCNT) + return (EINVAL); + + ndelay = (flag & (FNDELAY | FNONBLOCK)) ? B_TRUE : B_FALSE; + /* * lofiadm -a /dev/lofi/1 gets us here. */ @@ -447,16 +632,18 @@ lofi_open(dev_t *devp, int flag, int otyp, struct cred *credp) mutex_enter(&lofi_lock); - minor = getminor(*devp); + id = LOFI_MINOR2ID(getminor(*devp)); + part = LOFI_PART(getminor(*devp)); + mask = (1U << part); /* master control device */ - if (minor == 0) { + if (id == 0) { mutex_exit(&lofi_lock); return (0); } /* otherwise, the mapping should already exist */ - lsp = ddi_get_soft_state(lofi_statep, minor); + lsp = ddi_get_soft_state(lofi_statep, id); if (lsp == NULL) { mutex_exit(&lofi_lock); return (EINVAL); @@ -472,9 +659,53 @@ lofi_open(dev_t *devp, int flag, int otyp, struct cred *credp) return (EROFS); } - if (mark_opened(lsp, otyp) == -1) { + if ((lsp->ls_open_excl) & (mask)) { mutex_exit(&lofi_lock); - return (EINVAL); + return (EBUSY); + } + + if (flag & FEXCL) { + if (lsp->ls_open_lyr[part]) { + mutex_exit(&lofi_lock); + return (EBUSY); + } + for (int i = 0; i < OTYP_LYR; i++) { + if (lsp->ls_open_reg[i] & mask) { + mutex_exit(&lofi_lock); + return (EBUSY); + } + } + } + + if (lsp->ls_cmlbhandle != NULL) { + if (cmlb_validate(lsp->ls_cmlbhandle, 0, 0) != 0) { + /* + * non-blocking opens are allowed to succeed to + * support format and fdisk to create partitioning. + */ + if (!ndelay) { + mutex_exit(&lofi_lock); + return (ENXIO); + } + } else if (cmlb_partinfo(lsp->ls_cmlbhandle, part, &nblks, &lba, + NULL, NULL, 0) == 0) { + if ((!nblks) && ((!ndelay) || (otyp != OTYP_CHR))) { + mutex_exit(&lofi_lock); + return (ENXIO); + } + } else if (!ndelay) { + mutex_exit(&lofi_lock); + return (ENXIO); + } + } + + if (otyp == OTYP_LYR) { + lsp->ls_open_lyr[part]++; + } else { + lsp->ls_open_reg[otyp] |= mask; + } + if (flag & FEXCL) { + lsp->ls_open_excl |= mask; } mutex_exit(&lofi_lock); @@ -485,23 +716,35 @@ lofi_open(dev_t *devp, int flag, int otyp, struct cred *credp) static int lofi_close(dev_t dev, int flag, int otyp, struct cred *credp) { - minor_t minor; + minor_t part; + int id; + uint64_t mask; struct lofi_state *lsp; + id = LOFI_MINOR2ID(getminor(dev)); + part = LOFI_PART(getminor(dev)); + mask = (1U << part); + mutex_enter(&lofi_lock); - minor = getminor(dev); - lsp = ddi_get_soft_state(lofi_statep, minor); + lsp = ddi_get_soft_state(lofi_statep, id); if (lsp == NULL) { mutex_exit(&lofi_lock); return (EINVAL); } - if (minor == 0) { + if (id == 0) { mutex_exit(&lofi_lock); return (0); } - mark_closed(lsp, otyp); + if (lsp->ls_open_excl & mask) + lsp->ls_open_excl &= ~mask; + + if (otyp == OTYP_LYR) { + lsp->ls_open_lyr[part]--; + } else { + lsp->ls_open_reg[otyp] &= ~mask; + } /* * If we forcibly closed the underlying device (li_force), or @@ -509,7 +752,7 @@ lofi_close(dev_t dev, int flag, int otyp, struct cred *credp) * out of the door. */ if (!is_opened(lsp) && (lsp->ls_cleanup || lsp->ls_vp == NULL)) { - lofi_free_dev(lsp->ls_dev); + lofi_free_dev(lsp); lofi_destroy(lsp, credp); } @@ -970,7 +1213,7 @@ gzip_decompress(void *src, size_t srclen, void *dst, /*ARGSUSED*/ static int lzma_decompress(void *src, size_t srclen, void *dst, - size_t *dstlen, int level) + size_t *dstlen, int level) { size_t insizepure; void *actual_src; @@ -1005,7 +1248,9 @@ lofi_strategy_task(void *arg) size_t xfersize; boolean_t bufinited = B_FALSE; - lsp = ddi_get_soft_state(lofi_statep, getminor(bp->b_edev)); + lsp = ddi_get_soft_state(lofi_statep, + LOFI_MINOR2ID(getminor(bp->b_edev))); + if (lsp == NULL) { error = ENXIO; goto errout; @@ -1015,9 +1260,15 @@ lofi_strategy_task(void *arg) kstat_waitq_to_runq(KSTAT_IO_PTR(lsp->ls_kstat)); mutex_exit(lsp->ls_kstat->ks_lock); } + + mutex_enter(&lsp->ls_vp_lock); + lsp->ls_vp_iocount++; + mutex_exit(&lsp->ls_vp_lock); + bp_mapin(bp); bufaddr = bp->b_un.b_addr; - offset = bp->b_lblkno * DEV_BSIZE; /* offset within file */ + offset = (bp->b_lblkno + (diskaddr_t)(uintptr_t)bp->b_private) + << lsp->ls_lbshift; /* offset within file */ if (lsp->ls_crypto_enabled) { /* encrypted data really begins after crypto header */ offset += lsp->ls_crypto_offset; @@ -1345,6 +1596,10 @@ lofi_strategy(struct buf *bp) { struct lofi_state *lsp; offset_t offset; + minor_t part; + diskaddr_t p_lba; + diskaddr_t p_nblks; + int shift; /* * We cannot just do I/O here, because the current thread @@ -1357,12 +1612,38 @@ lofi_strategy(struct buf *bp) * do the I/O asynchronously, or we could use task queues. task * queues were incredibly easy so they win. */ - lsp = ddi_get_soft_state(lofi_statep, getminor(bp->b_edev)); + + lsp = ddi_get_soft_state(lofi_statep, + LOFI_MINOR2ID(getminor(bp->b_edev))); + part = LOFI_PART(getminor(bp->b_edev)); + if (lsp == NULL) { bioerror(bp, ENXIO); biodone(bp); return (0); } + shift = lsp->ls_lbshift; + + p_lba = 0; + p_nblks = lsp->ls_vp_size >> shift; + + if (lsp->ls_cmlbhandle != NULL) { + if (cmlb_partinfo(lsp->ls_cmlbhandle, part, &p_nblks, &p_lba, + NULL, NULL, 0)) { + bioerror(bp, ENXIO); + biodone(bp); + return (0); + } + } + + /* start block past partition end? */ + if (bp->b_lblkno > p_nblks) { + bioerror(bp, ENXIO); + biodone(bp); + return (0); + } + + offset = (bp->b_lblkno+p_lba) << shift; /* offset within file */ mutex_enter(&lsp->ls_vp_lock); if (lsp->ls_vp == NULL || lsp->ls_vp_closereq) { @@ -1372,12 +1653,14 @@ lofi_strategy(struct buf *bp) return (0); } - offset = bp->b_lblkno * DEV_BSIZE; /* offset within file */ if (lsp->ls_crypto_enabled) { /* encrypted data really begins after crypto header */ offset += lsp->ls_crypto_offset; } - if (offset == lsp->ls_vp_size) { + + /* make sure we will not pass the file or partition size */ + if (offset == lsp->ls_vp_size || + offset == (((p_lba + p_nblks) << shift) + lsp->ls_crypto_offset)) { /* EOF */ if ((bp->b_flags & B_READ) != 0) { bp->b_resid = bp->b_bcount; @@ -1390,13 +1673,15 @@ lofi_strategy(struct buf *bp) mutex_exit(&lsp->ls_vp_lock); return (0); } - if (offset > lsp->ls_vp_size) { + if ((offset > lsp->ls_vp_size) || + (offset > (((p_lba + p_nblks) << shift) + lsp->ls_crypto_offset)) || + ((offset + bp->b_bcount) > ((p_lba + p_nblks) << shift))) { bioerror(bp, ENXIO); biodone(bp); mutex_exit(&lsp->ls_vp_lock); return (0); } - lsp->ls_vp_iocount++; + mutex_exit(&lsp->ls_vp_lock); if (lsp->ls_kstat) { @@ -1404,6 +1689,7 @@ lofi_strategy(struct buf *bp) kstat_waitq_enter(KSTAT_IO_PTR(lsp->ls_kstat)); mutex_exit(lsp->ls_kstat->ks_lock); } + bp->b_private = (void *)(uintptr_t)p_lba; /* partition start */ (void) taskq_dispatch(lsp->ls_taskq, lofi_strategy_task, bp, KM_SLEEP); return (0); } @@ -1452,91 +1738,320 @@ lofi_awrite(dev_t dev, struct aio_req *aio, struct cred *credp) static int lofi_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) { + struct lofi_state *lsp; + dev_t dev = (dev_t)arg; + int instance; + + instance = LOFI_MINOR2ID(getminor(dev)); switch (infocmd) { case DDI_INFO_DEVT2DEVINFO: - *result = lofi_dip; + lsp = ddi_get_soft_state(lofi_statep, instance); + if (lsp == NULL) + return (DDI_FAILURE); + *result = lsp->ls_dip; return (DDI_SUCCESS); case DDI_INFO_DEVT2INSTANCE: - *result = 0; + *result = (void *) (intptr_t)instance; return (DDI_SUCCESS); } return (DDI_FAILURE); } static int -lofi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +lofi_create_minor_nodes(struct lofi_state *lsp, boolean_t labeled) { - int error; + int error = 0; + int instance = ddi_get_instance(lsp->ls_dip); + + if (labeled == B_TRUE) { + cmlb_alloc_handle(&lsp->ls_cmlbhandle); + error = cmlb_attach(lsp->ls_dip, &lofi_tg_ops, DTYPE_DIRECT, + B_FALSE, B_FALSE, DDI_NT_BLOCK_CHAN, + CMLB_CREATE_P0_MINOR_NODE, lsp->ls_cmlbhandle, (void *)1); + + if (error != DDI_SUCCESS) { + cmlb_free_handle(&lsp->ls_cmlbhandle); + lsp->ls_cmlbhandle = NULL; + error = ENXIO; + } + } else { + /* create minor nodes */ + error = ddi_create_minor_node(lsp->ls_dip, LOFI_BLOCK_NODE, + S_IFBLK, LOFI_ID2MINOR(instance), DDI_PSEUDO, 0); + if (error == DDI_SUCCESS) { + error = ddi_create_minor_node(lsp->ls_dip, + LOFI_CHAR_NODE, S_IFCHR, LOFI_ID2MINOR(instance), + DDI_PSEUDO, 0); + if (error != DDI_SUCCESS) { + ddi_remove_minor_node(lsp->ls_dip, + LOFI_BLOCK_NODE); + error = ENXIO; + } + } else + error = ENXIO; + } + return (error); +} - if (cmd != DDI_ATTACH) - return (DDI_FAILURE); +static int +lofi_zone_bind(struct lofi_state *lsp) +{ + int error = 0; - lofi_minor_id = id_space_create("lofi_minor_id", 1, L_MAXMIN32 + 1); + mutex_enter(&curproc->p_lock); + if ((error = rctl_incr_lofi(curproc, curproc->p_zone, 1)) != 0) { + mutex_exit(&curproc->p_lock); + return (error); + } + mutex_exit(&curproc->p_lock); - if (!lofi_minor_id) - return (DDI_FAILURE); + if (ddi_prop_update_string(lsp->ls_dev, lsp->ls_dip, ZONE_PROP_NAME, + (char *)curproc->p_zone->zone_name) != DDI_PROP_SUCCESS) { + rctl_decr_lofi(curproc->p_zone, 1); + error = EINVAL; + } else { + zone_init_ref(&lsp->ls_zone); + zone_hold_ref(curzone, &lsp->ls_zone, ZONE_REF_LOFI); + } + return (error); +} - error = ddi_soft_state_zalloc(lofi_statep, 0); +static void +lofi_zone_unbind(struct lofi_state *lsp) +{ + (void) ddi_prop_remove(DDI_DEV_T_NONE, lsp->ls_dip, ZONE_PROP_NAME); + rctl_decr_lofi(curproc->p_zone, 1); + zone_rele_ref(&lsp->ls_zone, ZONE_REF_LOFI); +} + +static int +lofi_online_dev(dev_info_t *dip) +{ + boolean_t labeled; + int error; + int instance = ddi_get_instance(dip); + struct lofi_state *lsp; + + labeled = B_FALSE; + if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "labeled")) + labeled = B_TRUE; + + /* lsp alloc+init, soft state is freed in lofi_detach */ + error = ddi_soft_state_zalloc(lofi_statep, instance); if (error == DDI_FAILURE) { - id_space_destroy(lofi_minor_id); - return (DDI_FAILURE); + return (ENOMEM); } - error = ddi_create_minor_node(dip, LOFI_CTL_NODE, S_IFCHR, 0, - DDI_PSEUDO, NULL); - if (error == DDI_FAILURE) { - ddi_soft_state_free(lofi_statep, 0); - id_space_destroy(lofi_minor_id); - return (DDI_FAILURE); + + lsp = ddi_get_soft_state(lofi_statep, instance); + lsp->ls_dip = dip; + + if ((error = lofi_zone_bind(lsp)) != 0) + goto err; + + cv_init(&lsp->ls_vp_cv, NULL, CV_DRIVER, NULL); + mutex_init(&lsp->ls_comp_cache_lock, NULL, MUTEX_DRIVER, NULL); + mutex_init(&lsp->ls_comp_bufs_lock, NULL, MUTEX_DRIVER, NULL); + mutex_init(&lsp->ls_kstat_lock, NULL, MUTEX_DRIVER, NULL); + mutex_init(&lsp->ls_vp_lock, NULL, MUTEX_DRIVER, NULL); + + if ((error = lofi_create_minor_nodes(lsp, labeled)) != 0) { + lofi_zone_unbind(lsp); + goto lerr; } + /* driver handles kernel-issued IOCTLs */ if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, DDI_KERNEL_IOCTL, NULL, 0) != DDI_PROP_SUCCESS) { - ddi_remove_minor_node(dip, NULL); - ddi_soft_state_free(lofi_statep, 0); - id_space_destroy(lofi_minor_id); - return (DDI_FAILURE); + error = DDI_FAILURE; + goto merr; } - zone_key_create(&lofi_zone_key, NULL, lofi_zone_shutdown, NULL); + lsp->ls_kstat = kstat_create_zone(LOFI_DRIVER_NAME, instance, + NULL, "disk", KSTAT_TYPE_IO, 1, 0, getzoneid()); + if (lsp->ls_kstat == NULL) { + (void) ddi_prop_remove(DDI_DEV_T_NONE, lsp->ls_dip, + DDI_KERNEL_IOCTL); + error = ENOMEM; + goto merr; + } - lofi_dip = dip; - ddi_report_dev(dip); + lsp->ls_kstat->ks_lock = &lsp->ls_kstat_lock; + kstat_zone_add(lsp->ls_kstat, GLOBAL_ZONEID); + kstat_install(lsp->ls_kstat); return (DDI_SUCCESS); +merr: + if (lsp->ls_cmlbhandle != NULL) { + cmlb_detach(lsp->ls_cmlbhandle, 0); + cmlb_free_handle(&lsp->ls_cmlbhandle); + } + ddi_remove_minor_node(dip, NULL); + lofi_zone_unbind(lsp); +lerr: + mutex_destroy(&lsp->ls_comp_cache_lock); + mutex_destroy(&lsp->ls_comp_bufs_lock); + mutex_destroy(&lsp->ls_kstat_lock); + mutex_destroy(&lsp->ls_vp_lock); + cv_destroy(&lsp->ls_vp_cv); +err: + ddi_soft_state_free(lofi_statep, instance); + return (error); } +/*ARGSUSED*/ static int -lofi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +lofi_dev_callback(sysevent_t *ev, void *cookie) { - if (cmd != DDI_DETACH) - return (DDI_FAILURE); + nvlist_t *nvlist; + char *class, *driver; + char name[10]; + int32_t instance; - mutex_enter(&lofi_lock); + class = sysevent_get_class_name(ev); + if (strcmp(class, EC_DEV_ADD) && strcmp(class, EC_DEV_REMOVE)) + return (0); - if (!list_is_empty(&lofi_list)) { - mutex_exit(&lofi_lock); - return (DDI_FAILURE); + (void) sysevent_get_attr_list(ev, &nvlist); + driver = fnvlist_lookup_string(nvlist, DEV_DRIVER_NAME); + instance = fnvlist_lookup_int32(nvlist, DEV_INSTANCE); + + if (strcmp(driver, LOFI_DRIVER_NAME) != 0) { + fnvlist_free(nvlist); + return (0); } - lofi_dip = NULL; - ddi_remove_minor_node(dip, NULL); - ddi_prop_remove_all(dip); + /* + * insert or remove device info, then announce the change + * via cv_broadcast. + * This allows the MAP/UNMAP to monitor device change. + */ + (void) snprintf(name, sizeof (name), "%d", instance); + if (strcmp(class, EC_DEV_ADD) == 0) { + mutex_enter(&lofi_chan_lock); + fnvlist_add_nvlist(lofi_devlink_cache, name, nvlist); + cv_broadcast(&lofi_chan_cv); + mutex_exit(&lofi_chan_lock); + } else if (strcmp(class, EC_DEV_REMOVE) == 0) { + mutex_enter(&lofi_chan_lock); + /* Can not use fnvlist_remove() as we can get ENOENT. */ + (void) nvlist_remove_all(lofi_devlink_cache, name); + cv_broadcast(&lofi_chan_cv); + mutex_exit(&lofi_chan_lock); + } + + fnvlist_free(nvlist); + return (0); +} - mutex_exit(&lofi_lock); +static int +lofi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + int rv; + int instance = ddi_get_instance(dip); + struct lofi_state *lsp; + if (cmd != DDI_ATTACH) + return (DDI_FAILURE); + + /* + * Instance 0 is control instance, attaching control instance + * will set the lofi up and ready. + */ + if (instance == 0) { + rv = ddi_soft_state_zalloc(lofi_statep, 0); + if (rv == DDI_FAILURE) { + return (DDI_FAILURE); + } + lsp = ddi_get_soft_state(lofi_statep, instance); + rv = ddi_create_minor_node(dip, LOFI_CTL_NODE, S_IFCHR, 0, + DDI_PSEUDO, 0); + if (rv == DDI_FAILURE) { + ddi_soft_state_free(lofi_statep, 0); + return (DDI_FAILURE); + } + /* driver handles kernel-issued IOCTLs */ + if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, + DDI_KERNEL_IOCTL, NULL, 0) != DDI_PROP_SUCCESS) { + ddi_remove_minor_node(dip, NULL); + ddi_soft_state_free(lofi_statep, 0); + return (DDI_FAILURE); + } + + rv = sysevent_evc_bind(DEVFS_CHANNEL, &lofi_chan, + EVCH_CREAT | EVCH_HOLD_PEND); + if (rv == 0) { + rv = sysevent_evc_subscribe(lofi_chan, "lofi", + EC_ALL, lofi_dev_callback, NULL, 0); + rv |= sysevent_evc_subscribe(lofi_chan, "disk", + EC_ALL, lofi_dev_callback, NULL, 0); + } else + lofi_chan = NULL; + if (rv != 0) { + if (lofi_chan != NULL) + (void) sysevent_evc_unbind(lofi_chan); + ddi_prop_remove_all(dip); + ddi_remove_minor_node(dip, NULL); + ddi_soft_state_free(lofi_statep, 0); + return (DDI_FAILURE); + } + zone_key_create(&lofi_zone_key, NULL, lofi_zone_shutdown, NULL); + + lsp->ls_dip = dip; + } else { + if (lofi_online_dev(dip) == DDI_FAILURE) + return (DDI_FAILURE); + } + + ddi_report_dev(dip); + return (DDI_SUCCESS); +} + +static int +lofi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + struct lofi_state *lsp; + int instance = ddi_get_instance(dip); + + if (cmd != DDI_DETACH) + return (DDI_FAILURE); + + /* + * If the instance is not 0, release state. + * The instance 0 is control device, we can not detach it + * before other instances are detached. + */ + if (instance != 0) { + lsp = ddi_get_soft_state(lofi_statep, instance); + if (lsp != NULL && lsp->ls_vp_ready == B_FALSE) { + ddi_soft_state_free(lofi_statep, instance); + return (DDI_SUCCESS); + } else + return (DDI_FAILURE); + } + mutex_enter(&lofi_lock); + + if (!list_is_empty(&lofi_list)) { + mutex_exit(&lofi_lock); + return (DDI_FAILURE); + } + + ddi_remove_minor_node(dip, NULL); + ddi_prop_remove_all(dip); + + mutex_exit(&lofi_lock); + + (void) sysevent_evc_unbind(lofi_chan); if (zone_key_delete(lofi_zone_key) != 0) cmn_err(CE_WARN, "failed to delete zone key"); ddi_soft_state_free(lofi_statep, 0); - id_space_destroy(lofi_minor_id); - return (DDI_SUCCESS); } /* - * With addition of encryption, be careful that encryption key is wiped before - * kernel memory structures are freed, and also that key is not accidentally - * passed out into userland structures. + * With the addition of encryption, we must be careful that encryption key is + * wiped before kernel's data structures are freed so it cannot accidentally + * slip out to userland through uninitialized data elsewhere. */ static void free_lofi_ioctl(struct lofi_ioctl *klip) @@ -1547,7 +2062,7 @@ free_lofi_ioctl(struct lofi_ioctl *klip) } /* - * These two just simplify the rest of the ioctls that need to copyin/out + * These two functions simplify the rest of the ioctls that need to copyin/out * the lofi_ioctl structure. */ int @@ -1564,11 +2079,12 @@ copy_in_lofi_ioctl(const struct lofi_ioctl *ulip, struct lofi_ioctl **klipp, /* ensure NULL termination */ klip->li_filename[MAXPATHLEN-1] = '\0'; + klip->li_devpath[MAXPATHLEN-1] = '\0'; klip->li_algorithm[MAXALGLEN-1] = '\0'; klip->li_cipher[CRYPTO_MAX_MECH_NAME-1] = '\0'; klip->li_iv_cipher[CRYPTO_MAX_MECH_NAME-1] = '\0'; - if (klip->li_minor > L_MAXMIN32) { + if (klip->li_id > L_MAXMIN32) { error = EINVAL; goto err; } @@ -1582,7 +2098,7 @@ err: int copy_out_lofi_ioctl(const struct lofi_ioctl *klip, struct lofi_ioctl *ulip, - int flag) + int flag) { int error; @@ -1698,12 +2214,9 @@ file_to_lofi(char *filename, boolean_t readonly, struct lofi_state **lspp) } /* - * Fakes up a disk geometry, and one big partition, based on the size - * of the file. This is needed because we allow newfs'ing the device, - * and newfs will do several disk ioctls to figure out the geometry and - * partition information. It uses that information to determine the parameters - * to pass to mkfs. Geometry is pretty much irrelevant these days, but we - * have to support it. + * Fakes up a disk geometry based on the size of the file. This is needed + * to support newfs on traditional lofi device, but also will provide + * geometry hint for cmlb. */ static void fake_disk_geometry(struct lofi_state *lsp) @@ -1722,6 +2235,7 @@ fake_disk_geometry(struct lofi_state *lsp) * for a small file, or so many on a big file that you waste space * for backup superblocks or cylinder group structures. */ + bzero(&lsp->ls_dkg, sizeof (lsp->ls_dkg)); if (dsize < (2 * 1024 * 1024)) /* floppy? */ lsp->ls_dkg.dkg_ncyl = dsize / (100 * 1024); else @@ -1729,70 +2243,74 @@ fake_disk_geometry(struct lofi_state *lsp) /* in case file file is < 100k */ if (lsp->ls_dkg.dkg_ncyl == 0) lsp->ls_dkg.dkg_ncyl = 1; - lsp->ls_dkg.dkg_acyl = 0; - lsp->ls_dkg.dkg_bcyl = 0; + + lsp->ls_dkg.dkg_pcyl = lsp->ls_dkg.dkg_ncyl; lsp->ls_dkg.dkg_nhead = 1; - lsp->ls_dkg.dkg_obs1 = 0; - lsp->ls_dkg.dkg_intrlv = 0; - lsp->ls_dkg.dkg_obs2 = 0; - lsp->ls_dkg.dkg_obs3 = 0; - lsp->ls_dkg.dkg_apc = 0; lsp->ls_dkg.dkg_rpm = 7200; - lsp->ls_dkg.dkg_pcyl = lsp->ls_dkg.dkg_ncyl + lsp->ls_dkg.dkg_acyl; - lsp->ls_dkg.dkg_nsect = dsize / (DEV_BSIZE * lsp->ls_dkg.dkg_ncyl); - lsp->ls_dkg.dkg_write_reinstruct = 0; - lsp->ls_dkg.dkg_read_reinstruct = 0; - - /* vtoc - see dkio(7I) */ - bzero(&lsp->ls_vtoc, sizeof (struct vtoc)); - lsp->ls_vtoc.v_sanity = VTOC_SANE; - lsp->ls_vtoc.v_version = V_VERSION; - (void) strncpy(lsp->ls_vtoc.v_volume, LOFI_DRIVER_NAME, - sizeof (lsp->ls_vtoc.v_volume)); - lsp->ls_vtoc.v_sectorsz = DEV_BSIZE; - lsp->ls_vtoc.v_nparts = 1; - lsp->ls_vtoc.v_part[0].p_tag = V_UNASSIGNED; + + lsp->ls_dkg.dkg_nsect = dsize / + (lsp->ls_dkg.dkg_ncyl << lsp->ls_pbshift); +} + +/* + * build vtoc - see dkio(7I) + * + * Fakes one big partition based on the size of the file. This is needed + * because we allow newfs'ing the traditional lofi device and newfs will + * do several disk ioctls to figure out the geometry and partition information. + * It uses that information to determine the parameters to pass to mkfs. + */ +static void +fake_disk_vtoc(struct lofi_state *lsp, struct vtoc *vt) +{ + bzero(vt, sizeof (struct vtoc)); + vt->v_sanity = VTOC_SANE; + vt->v_version = V_VERSION; + (void) strncpy(vt->v_volume, LOFI_DRIVER_NAME, + sizeof (vt->v_volume)); + vt->v_sectorsz = 1 << lsp->ls_pbshift; + vt->v_nparts = 1; + vt->v_part[0].p_tag = V_UNASSIGNED; /* * A compressed file is read-only, other files can * be read-write */ if (lsp->ls_uncomp_seg_sz > 0) { - lsp->ls_vtoc.v_part[0].p_flag = V_UNMNT | V_RONLY; + vt->v_part[0].p_flag = V_UNMNT | V_RONLY; } else { - lsp->ls_vtoc.v_part[0].p_flag = V_UNMNT; + vt->v_part[0].p_flag = V_UNMNT; } - lsp->ls_vtoc.v_part[0].p_start = (daddr_t)0; + vt->v_part[0].p_start = (daddr_t)0; /* * The partition size cannot just be the number of sectors, because * that might not end on a cylinder boundary. And if that's the case, * newfs/mkfs will print a scary warning. So just figure the size * based on the number of cylinders and sectors/cylinder. */ - lsp->ls_vtoc.v_part[0].p_size = lsp->ls_dkg.dkg_pcyl * + vt->v_part[0].p_size = lsp->ls_dkg.dkg_pcyl * lsp->ls_dkg.dkg_nsect * lsp->ls_dkg.dkg_nhead; +} - /* dk_cinfo - see dkio(7I) */ - bzero(&lsp->ls_ci, sizeof (struct dk_cinfo)); - (void) strcpy(lsp->ls_ci.dki_cname, LOFI_DRIVER_NAME); - lsp->ls_ci.dki_ctype = DKC_MD; - lsp->ls_ci.dki_flags = 0; - lsp->ls_ci.dki_cnum = 0; - lsp->ls_ci.dki_addr = 0; - lsp->ls_ci.dki_space = 0; - lsp->ls_ci.dki_prio = 0; - lsp->ls_ci.dki_vec = 0; - (void) strcpy(lsp->ls_ci.dki_dname, LOFI_DRIVER_NAME); - lsp->ls_ci.dki_unit = 0; - lsp->ls_ci.dki_slave = 0; - lsp->ls_ci.dki_partition = 0; +/* + * build dk_cinfo - see dkio(7I) + */ +static void +fake_disk_info(dev_t dev, struct dk_cinfo *ci) +{ + bzero(ci, sizeof (struct dk_cinfo)); + (void) strlcpy(ci->dki_cname, LOFI_DRIVER_NAME, sizeof (ci->dki_cname)); + ci->dki_ctype = DKC_SCSI_CCS; + (void) strlcpy(ci->dki_dname, LOFI_DRIVER_NAME, sizeof (ci->dki_dname)); + ci->dki_unit = LOFI_MINOR2ID(getminor(dev)); + ci->dki_partition = LOFI_PART(getminor(dev)); /* * newfs uses this to set maxcontig. Must not be < 16, or it * will be 0 when newfs multiplies it by DEV_BSIZE and divides * it by the block size. Then tunefs doesn't work because * maxcontig is 0. */ - lsp->ls_ci.dki_maxtransfer = 16; + ci->dki_maxtransfer = 16; } /* @@ -2110,21 +2628,177 @@ lofi_init_compress(struct lofi_state *lsp) } /* + * Allocate new or proposed id from lofi_id. + * + * Special cases for proposed id: + * 0: not allowed, 0 is id for control device. + * -1: allocate first usable id from lofi_id. + * any other value is proposed value from userland + * + * returns DDI_SUCCESS or errno. + */ +static int +lofi_alloc_id(int *idp) +{ + int id, error = DDI_SUCCESS; + + if (*idp == -1) { + id = id_allocff_nosleep(lofi_id); + if (id == -1) { + error = EAGAIN; + goto err; + } + } else if (*idp == 0) { + error = EINVAL; + goto err; + } else if (*idp > ((1 << (L_BITSMINOR - LOFI_CMLB_SHIFT)) - 1)) { + error = ERANGE; + goto err; + } else { + if (ddi_get_soft_state(lofi_statep, *idp) != NULL) { + error = EEXIST; + goto err; + } + + id = id_alloc_specific_nosleep(lofi_id, *idp); + if (id == -1) { + error = EAGAIN; + goto err; + } + } + *idp = id; +err: + return (error); +} + +static int +lofi_create_dev(struct lofi_ioctl *klip) +{ + dev_info_t *parent, *child; + struct lofi_state *lsp = NULL; + char namebuf[MAXNAMELEN]; + int error, circ; + + /* get control device */ + lsp = ddi_get_soft_state(lofi_statep, 0); + parent = ddi_get_parent(lsp->ls_dip); + + if ((error = lofi_alloc_id((int *)&klip->li_id))) + return (error); + + (void) snprintf(namebuf, sizeof (namebuf), LOFI_DRIVER_NAME "@%d", + klip->li_id); + + ndi_devi_enter(parent, &circ); + child = ndi_devi_findchild(parent, namebuf); + ndi_devi_exit(parent, circ); + + if (child == NULL) { + child = ddi_add_child(parent, LOFI_DRIVER_NAME, + (pnode_t)DEVI_SID_NODEID, klip->li_id); + if ((error = ddi_prop_update_int(DDI_DEV_T_NONE, child, + "instance", klip->li_id)) != DDI_PROP_SUCCESS) + goto err; + + if (klip->li_labeled == B_TRUE) { + if ((error = ddi_prop_create(DDI_DEV_T_NONE, child, + DDI_PROP_CANSLEEP, "labeled", 0, 0)) + != DDI_PROP_SUCCESS) + goto err; + } + + if ((error = ndi_devi_online(child, NDI_ONLINE_ATTACH)) + != NDI_SUCCESS) + goto err; + } else { + id_free(lofi_id, klip->li_id); + error = EEXIST; + return (error); + } + + goto done; + +err: + ddi_prop_remove_all(child); + (void) ndi_devi_offline(child, NDI_DEVI_REMOVE); + id_free(lofi_id, klip->li_id); +done: + + return (error); +} + +static void +lofi_create_inquiry(struct lofi_state *lsp, struct scsi_inquiry *inq) +{ + char *p = NULL; + + (void) strlcpy(inq->inq_vid, LOFI_DRIVER_NAME, sizeof (inq->inq_vid)); + + mutex_enter(&lsp->ls_vp_lock); + if (lsp->ls_vp != NULL) + p = strrchr(lsp->ls_vp->v_path, '/'); + if (p != NULL) + (void) strncpy(inq->inq_pid, p + 1, sizeof (inq->inq_pid)); + mutex_exit(&lsp->ls_vp_lock); + (void) strlcpy(inq->inq_revision, "1.0", sizeof (inq->inq_revision)); +} + +/* + * copy devlink name from event cache + */ +static void +lofi_copy_devpath(struct lofi_ioctl *klip) +{ + int error; + char namebuf[MAXNAMELEN], *str; + clock_t ticks; + nvlist_t *nvl; + + if (klip->li_labeled == B_TRUE) + klip->li_devpath[0] = '\0'; + else { + /* no need to wait for messages */ + (void) snprintf(klip->li_devpath, sizeof (klip->li_devpath), + "/dev/" LOFI_CHAR_NAME "/%d", klip->li_id); + return; + } + + (void) snprintf(namebuf, sizeof (namebuf), "%d", klip->li_id); + ticks = ddi_get_lbolt() + LOFI_TIMEOUT * drv_usectohz(1000000); + + nvl = NULL; + + mutex_enter(&lofi_chan_lock); + while (nvlist_lookup_nvlist(lofi_devlink_cache, namebuf, &nvl) != 0) { + error = cv_timedwait(&lofi_chan_cv, &lofi_chan_lock, ticks); + if (error == -1) + break; + } + + if (nvl != NULL) { + if (nvlist_lookup_string(nvl, DEV_NAME, &str) == 0) { + (void) strlcpy(klip->li_devpath, str, + sizeof (klip->li_devpath)); + } + } + mutex_exit(&lofi_chan_lock); +} + +/* * map a file to a minor number. Return the minor number. */ static int lofi_map_file(dev_t dev, struct lofi_ioctl *ulip, int pickminor, int *rvalp, struct cred *credp, int ioctl_flag) { - minor_t minor = (minor_t)-1; + int id = -1; struct lofi_state *lsp = NULL; struct lofi_ioctl *klip; int error; struct vnode *vp = NULL; vattr_t vattr; int flag; - dev_t newdev; - char namebuf[50]; + char namebuf[MAXNAMELEN]; error = copy_in_lofi_ioctl(ulip, &klip, ioctl_flag); if (error != 0) @@ -2132,38 +2806,12 @@ lofi_map_file(dev_t dev, struct lofi_ioctl *ulip, int pickminor, mutex_enter(&lofi_lock); - mutex_enter(&curproc->p_lock); - if ((error = rctl_incr_lofi(curproc, curproc->p_zone, 1)) != 0) { - mutex_exit(&curproc->p_lock); - mutex_exit(&lofi_lock); - free_lofi_ioctl(klip); - return (error); - } - mutex_exit(&curproc->p_lock); - if (file_to_lofi_nocheck(klip->li_filename, klip->li_readonly, NULL) == 0) { error = EBUSY; goto err; } - if (pickminor) { - minor = (minor_t)id_allocff_nosleep(lofi_minor_id); - if (minor == (minor_t)-1) { - error = EAGAIN; - goto err; - } - } else { - if (ddi_get_soft_state(lofi_statep, klip->li_minor) != NULL) { - error = EEXIST; - goto err; - } - - minor = (minor_t) - id_alloc_specific_nosleep(lofi_minor_id, klip->li_minor); - ASSERT(minor != (minor_t)-1); - } - flag = FREAD | FWRITE | FOFFMAX | FEXCL; error = vn_open(klip->li_filename, UIO_SYSSPACE, flag, 0, &vp, 0, 0); if (error) { @@ -2191,35 +2839,22 @@ lofi_map_file(dev_t dev, struct lofi_ioctl *ulip, int pickminor, goto err; } - /* lsp alloc+init */ - - error = ddi_soft_state_zalloc(lofi_statep, minor); - if (error == DDI_FAILURE) { - error = ENOMEM; - goto err; + if (pickminor) { + klip->li_id = (uint32_t)-1; } + if ((error = lofi_create_dev(klip)) != 0) + goto err; - lsp = ddi_get_soft_state(lofi_statep, minor); - list_insert_tail(&lofi_list, lsp); - - newdev = makedevice(getmajor(dev), minor); - lsp->ls_dev = newdev; - zone_init_ref(&lsp->ls_zone); - zone_hold_ref(curzone, &lsp->ls_zone, ZONE_REF_LOFI); - lsp->ls_uncomp_seg_sz = 0; - lsp->ls_comp_algorithm[0] = '\0'; - lsp->ls_crypto_offset = 0; - - cv_init(&lsp->ls_vp_cv, NULL, CV_DRIVER, NULL); - mutex_init(&lsp->ls_comp_cache_lock, NULL, MUTEX_DRIVER, NULL); - mutex_init(&lsp->ls_comp_bufs_lock, NULL, MUTEX_DRIVER, NULL); - mutex_init(&lsp->ls_kstat_lock, NULL, MUTEX_DRIVER, NULL); - mutex_init(&lsp->ls_vp_lock, NULL, MUTEX_DRIVER, NULL); + id = klip->li_id; + lsp = ddi_get_soft_state(lofi_statep, id); + if (lsp == NULL) + goto err; - (void) snprintf(namebuf, sizeof (namebuf), "%s_taskq_%d", - LOFI_DRIVER_NAME, minor); - lsp->ls_taskq = taskq_create_proc(namebuf, lofi_taskq_nthreads, - minclsyspri, 1, lofi_taskq_maxalloc, curzone->zone_zsched, 0); + /* + * from this point lofi_destroy() is used to clean up on error + * make sure the basic data is set + */ + lsp->ls_dev = makedevice(getmajor(dev), LOFI_ID2MINOR(id)); list_create(&lsp->ls_comp_cache, sizeof (struct lofi_comp_cache), offsetof(struct lofi_comp_cache, lc_list)); @@ -2232,6 +2867,10 @@ lofi_map_file(dev_t dev, struct lofi_ioctl *ulip, int pickminor, lsp->ls_vp = vp; lsp->ls_stacked_vp = vp; + + lsp->ls_vp_size = vattr.va_size; + lsp->ls_vp_comp_size = lsp->ls_vp_size; + /* * Try to handle stacked lofs vnodes. */ @@ -2249,21 +2888,18 @@ lofi_map_file(dev_t dev, struct lofi_ioctl *ulip, int pickminor, } } - lsp->ls_vp_size = vattr.va_size; - lsp->ls_vp_comp_size = lsp->ls_vp_size; - - lsp->ls_kstat = kstat_create_zone(LOFI_DRIVER_NAME, minor, - NULL, "disk", KSTAT_TYPE_IO, 1, 0, getzoneid()); - - if (lsp->ls_kstat == NULL) { - error = ENOMEM; - goto err; - } - - lsp->ls_kstat->ks_lock = &lsp->ls_kstat_lock; - kstat_zone_add(lsp->ls_kstat, GLOBAL_ZONEID); + lsp->ls_lbshift = highbit(DEV_BSIZE) - 1; + lsp->ls_pbshift = lsp->ls_lbshift; lsp->ls_readonly = klip->li_readonly; + lsp->ls_uncomp_seg_sz = 0; + lsp->ls_comp_algorithm[0] = '\0'; + lsp->ls_crypto_offset = 0; + + (void) snprintf(namebuf, sizeof (namebuf), "%s_taskq_%d", + LOFI_DRIVER_NAME, id); + lsp->ls_taskq = taskq_create_proc(namebuf, lofi_taskq_nthreads, + minclsyspri, 1, lofi_taskq_maxalloc, curzone->zone_zsched, 0); if ((error = lofi_init_crypto(lsp, klip)) != 0) goto err; @@ -2273,74 +2909,46 @@ lofi_map_file(dev_t dev, struct lofi_ioctl *ulip, int pickminor, fake_disk_geometry(lsp); - /* create minor nodes */ - - (void) snprintf(namebuf, sizeof (namebuf), "%d", minor); - error = ddi_create_minor_node(lofi_dip, namebuf, S_IFBLK, minor, - DDI_PSEUDO, NULL); - if (error != DDI_SUCCESS) { - error = ENXIO; - goto err; - } - - (void) snprintf(namebuf, sizeof (namebuf), "%d,raw", minor); - error = ddi_create_minor_node(lofi_dip, namebuf, S_IFCHR, minor, - DDI_PSEUDO, NULL); - if (error != DDI_SUCCESS) { - /* remove block node */ - (void) snprintf(namebuf, sizeof (namebuf), "%d", minor); - ddi_remove_minor_node(lofi_dip, namebuf); - error = ENXIO; - goto err; - } - - /* create DDI properties */ - - if ((ddi_prop_update_int64(newdev, lofi_dip, SIZE_PROP_NAME, + if ((ddi_prop_update_int64(lsp->ls_dev, lsp->ls_dip, SIZE_PROP_NAME, lsp->ls_vp_size - lsp->ls_crypto_offset)) != DDI_PROP_SUCCESS) { error = EINVAL; - goto nodeerr; + goto err; } - if ((ddi_prop_update_int64(newdev, lofi_dip, NBLOCKS_PROP_NAME, + if ((ddi_prop_update_int64(lsp->ls_dev, lsp->ls_dip, NBLOCKS_PROP_NAME, (lsp->ls_vp_size - lsp->ls_crypto_offset) / DEV_BSIZE)) != DDI_PROP_SUCCESS) { error = EINVAL; - goto nodeerr; - } - - if (ddi_prop_update_string(newdev, lofi_dip, ZONE_PROP_NAME, - (char *)curproc->p_zone->zone_name) != DDI_PROP_SUCCESS) { - error = EINVAL; - goto nodeerr; + goto err; } - kstat_install(lsp->ls_kstat); - + list_insert_tail(&lofi_list, lsp); + /* + * Notify we are ready to rock. + */ + mutex_enter(&lsp->ls_vp_lock); + lsp->ls_vp_ready = B_TRUE; + cv_broadcast(&lsp->ls_vp_cv); + mutex_exit(&lsp->ls_vp_lock); mutex_exit(&lofi_lock); + lofi_copy_devpath(klip); + if (rvalp) - *rvalp = (int)minor; - klip->li_minor = minor; + *rvalp = id; (void) copy_out_lofi_ioctl(klip, ulip, ioctl_flag); free_lofi_ioctl(klip); return (0); -nodeerr: - lofi_free_dev(newdev); err: if (lsp != NULL) { lofi_destroy(lsp, credp); } else { if (vp != NULL) { + (void) VOP_PUTPAGE(vp, 0, 0, B_INVAL, credp, NULL); (void) VOP_CLOSE(vp, flag, 1, 0, credp, NULL); VN_RELE(vp); } - - if (minor != (minor_t)-1) - id_free(lofi_minor_id, minor); - - rctl_decr_lofi(curproc->p_zone, 1); } mutex_exit(&lofi_lock); @@ -2357,6 +2965,9 @@ lofi_unmap_file(struct lofi_ioctl *ulip, int byfilename, { struct lofi_state *lsp; struct lofi_ioctl *klip; + nvlist_t *nvl = NULL; + clock_t ticks; + char name[MAXNAMELEN]; int err; err = copy_in_lofi_ioctl(ulip, &klip, ioctl_flag); @@ -2370,12 +2981,12 @@ lofi_unmap_file(struct lofi_ioctl *ulip, int byfilename, mutex_exit(&lofi_lock); return (err); } - } else if (klip->li_minor == 0) { + } else if (klip->li_id == 0) { mutex_exit(&lofi_lock); free_lofi_ioctl(klip); return (ENXIO); } else { - lsp = ddi_get_soft_state(lofi_statep, klip->li_minor); + lsp = ddi_get_soft_state(lofi_statep, klip->li_id); } if (lsp == NULL || lsp->ls_vp == NULL || lofi_access(lsp) != 0) { @@ -2384,7 +2995,7 @@ lofi_unmap_file(struct lofi_ioctl *ulip, int byfilename, return (ENXIO); } - klip->li_minor = getminor(lsp->ls_dev); + klip->li_id = LOFI_MINOR2ID(getminor(lsp->ls_dev)); /* * If it's still held open, we'll do one of three things: @@ -2432,9 +3043,27 @@ lofi_unmap_file(struct lofi_ioctl *ulip, int byfilename, } out: - lofi_free_dev(lsp->ls_dev); + lofi_free_dev(lsp); lofi_destroy(lsp, credp); + /* + * check the lofi_devlink_cache if device is really gone. + * note: we just wait for timeout here and dont give error if + * timer will expire. This check is to try to ensure the unmap is + * really done when lofiadm -d completes. + * Since lofi_lock is held, also hopefully the lofiadm -a calls + * wont interfere the the unmap. + */ + (void) snprintf(name, sizeof (name), "%d", klip->li_id); + ticks = ddi_get_lbolt() + LOFI_TIMEOUT * drv_usectohz(1000000); + mutex_enter(&lofi_chan_lock); + while (nvlist_lookup_nvlist(lofi_devlink_cache, name, &nvl) == 0) { + err = cv_timedwait(&lofi_chan_cv, &lofi_chan_lock, ticks); + if (err == -1) + break; + } + mutex_exit(&lofi_chan_lock); + mutex_exit(&lofi_lock); (void) copy_out_lofi_ioctl(klip, ulip, ioctl_flag); free_lofi_ioctl(klip); @@ -2460,13 +3089,13 @@ lofi_get_info(dev_t dev, struct lofi_ioctl *ulip, int which, switch (which) { case LOFI_GET_FILENAME: - if (klip->li_minor == 0) { + if (klip->li_id == 0) { free_lofi_ioctl(klip); return (EINVAL); } mutex_enter(&lofi_lock); - lsp = ddi_get_soft_state(lofi_statep, klip->li_minor); + lsp = ddi_get_soft_state(lofi_statep, klip->li_id); if (lsp == NULL || lofi_access(lsp) != 0) { mutex_exit(&lofi_lock); free_lofi_ioctl(klip); @@ -2484,11 +3113,14 @@ lofi_get_info(dev_t dev, struct lofi_ioctl *ulip, int which, } klip->li_readonly = lsp->ls_readonly; + klip->li_labeled = lsp->ls_cmlbhandle != NULL; (void) strlcpy(klip->li_algorithm, lsp->ls_comp_algorithm, sizeof (klip->li_algorithm)); klip->li_crypto_enabled = lsp->ls_crypto_enabled; mutex_exit(&lofi_lock); + + lofi_copy_devpath(klip); error = copy_out_lofi_ioctl(klip, ulip, ioctl_flag); free_lofi_ioctl(klip); return (error); @@ -2496,12 +3128,19 @@ lofi_get_info(dev_t dev, struct lofi_ioctl *ulip, int which, mutex_enter(&lofi_lock); error = file_to_lofi(klip->li_filename, klip->li_readonly, &lsp); - if (error == 0) - klip->li_minor = getminor(lsp->ls_dev); + if (error != 0) { + mutex_exit(&lofi_lock); + free_lofi_ioctl(klip); + return (error); + } + klip->li_id = LOFI_MINOR2ID(getminor(lsp->ls_dev)); + + klip->li_readonly = lsp->ls_readonly; + klip->li_labeled = lsp->ls_cmlbhandle != NULL; mutex_exit(&lofi_lock); - if (error == 0) - error = copy_out_lofi_ioctl(klip, ulip, ioctl_flag); + lofi_copy_devpath(klip); + error = copy_out_lofi_ioctl(klip, ulip, ioctl_flag); free_lofi_ioctl(klip); return (error); @@ -2515,7 +3154,7 @@ lofi_get_info(dev_t dev, struct lofi_ioctl *ulip, int which, return (error); } - klip->li_minor = getminor(lsp->ls_dev); + klip->li_id = LOFI_MINOR2ID(getminor(lsp->ls_dev)); (void) strlcpy(klip->li_algorithm, lsp->ls_comp_algorithm, sizeof (klip->li_algorithm)); @@ -2530,17 +3169,63 @@ lofi_get_info(dev_t dev, struct lofi_ioctl *ulip, int which, } static int +uscsi_is_inquiry(intptr_t arg, int flag, union scsi_cdb *cdb, + struct uscsi_cmd *uscmd) +{ + int rval; + +#ifdef _MULTI_DATAMODEL + switch (ddi_model_convert_from(flag & FMODELS)) { + case DDI_MODEL_ILP32: { + struct uscsi_cmd32 ucmd32; + + if (ddi_copyin((void *)arg, &ucmd32, sizeof (ucmd32), flag)) { + rval = EFAULT; + goto err; + } + uscsi_cmd32touscsi_cmd((&ucmd32), uscmd); + break; + } + case DDI_MODEL_NONE: + if (ddi_copyin((void *)arg, uscmd, sizeof (*uscmd), flag)) { + rval = EFAULT; + goto err; + } + break; + default: + rval = EFAULT; + goto err; + } +#else + if (ddi_copyin((void *)arg, uscmd, sizeof (*uscmd), flag)) { + rval = EFAULT; + goto err; + } +#endif /* _MULTI_DATAMODEL */ + if (ddi_copyin(uscmd->uscsi_cdb, cdb, uscmd->uscsi_cdblen, flag)) { + rval = EFAULT; + goto err; + } + if (cdb->scc_cmd == SCMD_INQUIRY) { + return (0); + } +err: + return (rval); +} + +static int lofi_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, int *rvalp) { int error; enum dkio_state dkstate; struct lofi_state *lsp; - minor_t minor; + int id; + + id = LOFI_MINOR2ID(getminor(dev)); - minor = getminor(dev); /* lofi ioctls only apply to the master device */ - if (minor == 0) { + if (id == 0) { struct lofi_ioctl *lip = (struct lofi_ioctl *)arg; /* @@ -2576,27 +3261,29 @@ lofi_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, * This API made limited sense when this value was fixed * at LOFI_MAX_FILES. However, its use to iterate * across all possible devices in lofiadm means we don't - * want to return L_MAXMIN32, but the highest - * *allocated* minor. + * want to return L_MAXMIN, but the highest + * *allocated* id. */ case LOFI_GET_MAXMINOR: - minor = 0; + id = 0; mutex_enter(&lofi_lock); for (lsp = list_head(&lofi_list); lsp != NULL; lsp = list_next(&lofi_list, lsp)) { + int i; if (lofi_access(lsp) != 0) continue; - if (getminor(lsp->ls_dev) > minor) - minor = getminor(lsp->ls_dev); + i = ddi_get_instance(lsp->ls_dip); + if (i > id) + id = i; } mutex_exit(&lofi_lock); - error = ddi_copyout(&minor, &lip->li_minor, - sizeof (minor), flag); + error = ddi_copyout(&id, &lip->li_id, + sizeof (id), flag); if (error) return (EFAULT); return (0); @@ -2610,13 +3297,21 @@ lofi_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, } mutex_enter(&lofi_lock); - lsp = ddi_get_soft_state(lofi_statep, minor); + lsp = ddi_get_soft_state(lofi_statep, id); if (lsp == NULL || lsp->ls_vp_closereq) { mutex_exit(&lofi_lock); return (ENXIO); } mutex_exit(&lofi_lock); + if (ddi_prop_exists(DDI_DEV_T_ANY, lsp->ls_dip, DDI_PROP_DONTPASS, + "labeled") == 1) { + error = cmlb_ioctl(lsp->ls_cmlbhandle, dev, cmd, arg, flag, + credp, rvalp, 0); + if (error != ENOTTY) + return (error); + } + /* * We explicitly allow DKIOCSTATE, but all other ioctls should fail with * EIO as if the device was no longer present. @@ -2626,12 +3321,44 @@ lofi_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, /* these are for faking out utilities like newfs */ switch (cmd) { - case DKIOCGVTOC: + case DKIOCGMEDIAINFO: + case DKIOCGMEDIAINFOEXT: { + struct dk_minfo_ext media_info; + int shift = lsp->ls_lbshift; + int size; + + if (cmd == DKIOCGMEDIAINFOEXT) { + media_info.dki_pbsize = 1U << lsp->ls_pbshift; + size = sizeof (struct dk_minfo_ext); + } else { + size = sizeof (struct dk_minfo); + } + + media_info.dki_media_type = DK_FIXED_DISK; + media_info.dki_lbsize = 1U << shift; + media_info.dki_capacity = + (lsp->ls_vp_size - lsp->ls_crypto_offset) >> shift; + + if (ddi_copyout(&media_info, (void *)arg, size, flag)) + return (EFAULT); + return (0); + } + case DKIOCREMOVABLE: { + int i = 0; + if (ddi_copyout(&i, (caddr_t)arg, sizeof (int), flag)) + return (EFAULT); + return (0); + } + + case DKIOCGVTOC: { + struct vtoc vt; + fake_disk_vtoc(lsp, &vt); + switch (ddi_model_convert_from(flag & FMODELS)) { case DDI_MODEL_ILP32: { struct vtoc32 vtoc32; - vtoctovtoc32(lsp->ls_vtoc, vtoc32); + vtoctovtoc32(vt, vtoc32); if (ddi_copyout(&vtoc32, (void *)arg, sizeof (struct vtoc32), flag)) return (EFAULT); @@ -2639,18 +3366,20 @@ lofi_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, } case DDI_MODEL_NONE: - if (ddi_copyout(&lsp->ls_vtoc, (void *)arg, + if (ddi_copyout(&vt, (void *)arg, sizeof (struct vtoc), flag)) return (EFAULT); break; } return (0); - case DKIOCINFO: - error = ddi_copyout(&lsp->ls_ci, (void *)arg, - sizeof (struct dk_cinfo), flag); - if (error) + } + case DKIOCINFO: { + struct dk_cinfo ci; + fake_disk_info(dev, &ci); + if (ddi_copyout(&ci, (void *)arg, sizeof (ci), flag)) return (EFAULT); return (0); + } case DKIOCG_VIRTGEOM: case DKIOCG_PHYGEOM: case DKIOCGGEOM: @@ -2697,11 +3426,80 @@ lofi_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, sizeof (dkstate), flag) != 0) return (EFAULT); return (0); + case USCSICMD: { + struct uscsi_cmd uscmd; + union scsi_cdb cdb; + + if (uscsi_is_inquiry(arg, flag, &cdb, &uscmd) == 0) { + struct scsi_inquiry inq = {0}; + + lofi_create_inquiry(lsp, &inq); + if (ddi_copyout(&inq, uscmd.uscsi_bufaddr, + uscmd.uscsi_buflen, flag) != 0) + return (EFAULT); + return (0); + } else if (cdb.scc_cmd == SCMD_READ_CAPACITY) { + struct scsi_capacity capacity; + + capacity.capacity = + BE_32((lsp->ls_vp_size - lsp->ls_crypto_offset) >> + lsp->ls_lbshift); + capacity.lbasize = BE_32(1 << lsp->ls_lbshift); + if (ddi_copyout(&capacity, uscmd.uscsi_bufaddr, + uscmd.uscsi_buflen, flag) != 0) + return (EFAULT); + return (0); + } + + uscmd.uscsi_rqstatus = 0xff; +#ifdef _MULTI_DATAMODEL + switch (ddi_model_convert_from(flag & FMODELS)) { + case DDI_MODEL_ILP32: { + struct uscsi_cmd32 ucmd32; + uscsi_cmdtouscsi_cmd32((&uscmd), (&ucmd32)); + if (ddi_copyout(&ucmd32, (void *)arg, sizeof (ucmd32), + flag) != 0) + return (EFAULT); + break; + } + case DDI_MODEL_NONE: + if (ddi_copyout(&uscmd, (void *)arg, sizeof (uscmd), + flag) != 0) + return (EFAULT); + break; + default: + return (EFAULT); + } +#else + if (ddi_copyout(&uscmd, (void *)arg, sizeof (uscmd), flag) != 0) + return (EFAULT); +#endif /* _MULTI_DATAMODEL */ + return (0); + } default: +#ifdef DEBUG + cmn_err(CE_WARN, "lofi_ioctl: %d is not implemented\n", cmd); +#endif /* DEBUG */ return (ENOTTY); } } +static int +lofi_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags, + char *name, caddr_t valuep, int *lengthp) +{ + struct lofi_state *lsp; + + lsp = ddi_get_soft_state(lofi_statep, ddi_get_instance(dip)); + if (lsp == NULL) { + return (ddi_prop_op(dev, dip, prop_op, mod_flags, + name, valuep, lengthp)); + } + + return (cmlb_prop_op(lsp->ls_cmlbhandle, dev, dip, prop_op, mod_flags, + name, valuep, lengthp, LOFI_PART(getminor(dev)), NULL)); +} + static struct cb_ops lofi_cb_ops = { lofi_open, /* open */ lofi_close, /* close */ @@ -2715,7 +3513,7 @@ static struct cb_ops lofi_cb_ops = { nodev, /* mmap */ nodev, /* segmap */ nochpoll, /* poll */ - ddi_prop_op, /* prop_op */ + lofi_prop_op, /* prop_op */ 0, /* streamtab */ D_64BIT | D_NEW | D_MP, /* Driver compatibility flag */ CB_REV, @@ -2758,17 +3556,43 @@ _init(void) list_create(&lofi_list, sizeof (struct lofi_state), offsetof(struct lofi_state, ls_list)); - error = ddi_soft_state_init(&lofi_statep, + error = ddi_soft_state_init((void **)&lofi_statep, sizeof (struct lofi_state), 0); - if (error) + if (error) { + list_destroy(&lofi_list); return (error); + } + + /* + * The minor number is stored as id << LOFI_CMLB_SHIFT as + * we need to reserve space for cmlb minor numbers. + * This will leave out 4096 id values on 32bit kernel, which should + * still suffice. + */ + lofi_id = id_space_create("lofi_id", 1, + (1 << (L_BITSMINOR - LOFI_CMLB_SHIFT))); + + if (lofi_id == NULL) { + ddi_soft_state_fini((void **)&lofi_statep); + list_destroy(&lofi_list); + return (DDI_FAILURE); + } mutex_init(&lofi_lock, NULL, MUTEX_DRIVER, NULL); + mutex_init(&lofi_chan_lock, NULL, MUTEX_DRIVER, NULL); + cv_init(&lofi_chan_cv, NULL, CV_DRIVER, NULL); + error = nvlist_alloc(&lofi_devlink_cache, NV_UNIQUE_NAME, KM_SLEEP); - error = mod_install(&modlinkage); + if (error == 0) + error = mod_install(&modlinkage); if (error) { + id_space_destroy(lofi_id); + if (lofi_devlink_cache != NULL) + nvlist_free(lofi_devlink_cache); + mutex_destroy(&lofi_chan_lock); + cv_destroy(&lofi_chan_cv); mutex_destroy(&lofi_lock); - ddi_soft_state_fini(&lofi_statep); + ddi_soft_state_fini((void **)&lofi_statep); list_destroy(&lofi_list); } @@ -2793,8 +3617,16 @@ _fini(void) if (error) return (error); + mutex_enter(&lofi_chan_lock); + nvlist_free(lofi_devlink_cache); + lofi_devlink_cache = NULL; + mutex_exit(&lofi_chan_lock); + + mutex_destroy(&lofi_chan_lock); + cv_destroy(&lofi_chan_cv); mutex_destroy(&lofi_lock); - ddi_soft_state_fini(&lofi_statep); + id_space_destroy(lofi_id); + ddi_soft_state_fini((void **)&lofi_statep); list_destroy(&lofi_list); return (error); diff --git a/usr/src/uts/common/os/log_sysevent.c b/usr/src/uts/common/os/log_sysevent.c index 51cfa7f817..9739d4dbdf 100644 --- a/usr/src/uts/common/os/log_sysevent.c +++ b/usr/src/uts/common/os/log_sysevent.c @@ -21,6 +21,7 @@ /* * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * Copyright 2016 Toomas Soome */ #include @@ -34,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -568,7 +570,7 @@ free_packed_event(sysevent_t *ev) */ int sysevent_add_attr(sysevent_attr_list_t **ev_attr_list, char *name, - sysevent_value_t *se_value, int flag) + sysevent_value_t *se_value, int flag) { int error; nvlist_t **nvlp = (nvlist_t **)ev_attr_list; @@ -1092,7 +1094,7 @@ find_subclass(class_lst_t *c_list, char *subclass) static void insert_subclass(class_lst_t *c_list, char **subclass_names, - int subclass_num, uint32_t sub_id) + int subclass_num, uint32_t sub_id) { int i, subclass_sz; subclass_lst_t *sc_list; @@ -1156,7 +1158,7 @@ remove_all_class(sysevent_channel_descriptor_t *chan, uint32_t sub_id) static void remove_class(sysevent_channel_descriptor_t *chan, uint32_t sub_id, - char *class_name) + char *class_name) { class_lst_t *c_list; subclass_lst_t *sc_list; @@ -1179,7 +1181,7 @@ remove_class(sysevent_channel_descriptor_t *chan, uint32_t sub_id, static int insert_class(sysevent_channel_descriptor_t *chan, char *event_class, - char **event_subclass_lst, int subclass_num, uint32_t sub_id) + char **event_subclass_lst, int subclass_num, uint32_t sub_id) { class_lst_t *c_list; @@ -1206,7 +1208,7 @@ insert_class(sysevent_channel_descriptor_t *chan, char *event_class, static int add_registration(sysevent_channel_descriptor_t *chan, uint32_t sub_id, - char *nvlbuf, size_t nvlsize) + char *nvlbuf, size_t nvlsize) { uint_t num_elem; char *event_class; @@ -1247,7 +1249,7 @@ add_registration(sysevent_channel_descriptor_t *chan, uint32_t sub_id, */ static int get_registration(sysevent_channel_descriptor_t *chan, char *databuf, - uint32_t *bufsz, uint32_t class_index) + uint32_t *bufsz, uint32_t class_index) { int num_classes = 0; char *nvlbuf = NULL; @@ -1733,6 +1735,49 @@ log_sysevent(sysevent_t *ev, int flag, sysevent_id_t *eid) } /* + * Publish EC_DEV_ADD and EC_DEV_REMOVE events from devfsadm to lofi. + * This interface is needed to pass device link names to the lofi driver, + * to be returned via ioctl() to the lofiadm command. + * The problem is, if lofiadm is executed in local zone, there is no + * mechanism to announce the device name from the /dev tree back to lofiadm, + * as sysevents are not accessible from local zone and devfsadmd is only + * running in global zone. + * + * Delayed/missed events are not fatal for lofi, as the device name returned + * to lofiadm is for information and can be re-queried with listing + * mappings with lofiadm command. + * + * Once we have a better method, this interface should be reworked. + */ +static void +notify_lofi(sysevent_t *ev) +{ + static evchan_t *devfs_chan = NULL; + nvlist_t *nvlist; + int ret; + + if ((strcmp(EC_DEV_ADD, sysevent_get_class_name(ev)) != 0) && + (strcmp(EC_DEV_REMOVE, sysevent_get_class_name(ev)) != 0)) + return; + + /* only bind once to avoid bind/unbind storm on busy system */ + if (devfs_chan == NULL) { + if ((ret = sysevent_evc_bind("devfsadm_event_channel", + &devfs_chan, EVCH_CREAT | EVCH_HOLD_PEND)) != 0) { + cmn_err(CE_CONT, "sysevent_evc_bind failed: %d\n", ret); + return; + } + } + + (void) sysevent_get_attr_list(ev, &nvlist); + (void) sysevent_evc_publish(devfs_chan, sysevent_get_class_name(ev), + sysevent_get_subclass_name(ev), "illumos", EC_DEVFS, nvlist, + EVCH_SLEEP); + + nvlist_free(nvlist); +} + +/* * log_usr_sysevent - user system event logger * Private to devfsadm and accessible only via * modctl(MODEVENTS, MODEVENTS_POST_EVENT) @@ -1758,6 +1803,8 @@ log_usr_sysevent(sysevent_t *ev, int ev_size, sysevent_id_t *eid) return (EFAULT); } + notify_lofi(ev_copy); + if ((ret = queue_sysevent(ev_copy, &new_eid, SE_NOSLEEP)) != 0) { if (ret == SE_ENOMEM || ret == SE_EQSIZE) return (EAGAIN); diff --git a/usr/src/uts/common/sys/cmlb.h b/usr/src/uts/common/sys/cmlb.h index 81e9c060f4..a1013c9fed 100644 --- a/usr/src/uts/common/sys/cmlb.h +++ b/usr/src/uts/common/sys/cmlb.h @@ -19,6 +19,7 @@ * CDDL HEADER END */ /* + * Copyright 2016 Toomas Soome * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -61,6 +62,7 @@ typedef struct tg_attribute { #define CMLB_OFF_BY_ONE 0x00000004 #define CMLB_FAKE_LABEL_ONE_PARTITION 0x00000008 #define CMLB_INTERNAL_MINOR_NODES 0x00000010 +#define CMLB_CREATE_P0_MINOR_NODE 0x00000020 /* bit definitions of flag passed to cmlb_validate */ #define CMLB_SILENT 0x00000001 @@ -80,6 +82,22 @@ typedef struct tg_attribute { #define TG_GETBLOCKSIZE 4 #define TG_GETATTR 5 +#if defined(_SUNOS_VTOC_8) + +#define CMLBUNIT_DFT_SHIFT 3 +/* This will support p0 node on sparc */ +#define CMLBUNIT_FORCE_P0_SHIFT (CMLBUNIT_DFT_SHIFT + 1) + +#elif defined(_SUNOS_VTOC_16) + +#define CMLBUNIT_DFT_SHIFT 6 +#define CMLBUNIT_FORCE_P0_SHIFT (CMLBUNIT_DFT_SHIFT) + +#else /* defined(_SUNOS_VTOC_16) */ + +#error "No VTOC format defined." + +#endif /* defined(_SUNOS_VTOC_8) */ /* * Ops vector including utility functions into target driver that cmlb uses. diff --git a/usr/src/uts/common/sys/cmlb_impl.h b/usr/src/uts/common/sys/cmlb_impl.h index 47ee3ab7bd..b64c4aa64b 100644 --- a/usr/src/uts/common/sys/cmlb_impl.h +++ b/usr/src/uts/common/sys/cmlb_impl.h @@ -20,6 +20,7 @@ */ /* + * Copyright 2016 Toomas Soome * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -42,7 +43,11 @@ extern "C" { #define FDISK_PARTS (FD_NUMPART + MAX_EXT_PARTS) #if defined(_SUNOS_VTOC_8) -#define NSDMAP NDKMAP +/* + * As lofi needs to support p0 on sparc in case of labeled virtual disks, + * define NDSMAP to support one extra entrie. + */ +#define NSDMAP (NDKMAP + 1) #elif defined(_SUNOS_VTOC_16) #define NSDMAP (NDKMAP + FDISK_PARTS + 1) #else @@ -51,11 +56,10 @@ extern "C" { #define MAXPART (NSDMAP + 1) #define WD_NODE 7 - +#define P0_RAW_DISK (NDKMAP) #if defined(__i386) || defined(__amd64) -#define P0_RAW_DISK (NDKMAP) #define FDISK_P1 (NDKMAP+1) #define FDISK_P2 (NDKMAP+2) #define FDISK_P3 (NDKMAP+3) @@ -82,21 +86,10 @@ extern "C" { #define ISCD(cl) (cl->cl_device_type == DTYPE_RODIRECT) #define ISHOTPLUGGABLE(cl) (cl->cl_is_hotpluggable) -#if defined(_SUNOS_VTOC_8) - -#define CMLBUNIT_SHIFT 3 -#define CMLBPART_MASK 7 - -#elif defined(_SUNOS_VTOC_16) - -#define CMLBUNIT_SHIFT 6 -#define CMLBPART_MASK 63 - -#else -#error "No VTOC format defined." -#endif +#define CMLBUNIT_SHIFT (CMLBUNIT_DFT_SHIFT) +#define CMLBPART_MASK ((1 << CMLBUNIT_SHIFT) - 1) -#define CMLBUNIT(dev) (getminor((dev)) >> CMLBUNIT_SHIFT) +#define CMLBUNIT(dev, shift) (getminor((dev)) >> (shift)) #define CMLBPART(dev) (getminor((dev)) & CMLBPART_MASK) /* diff --git a/usr/src/uts/common/sys/lofi.h b/usr/src/uts/common/sys/lofi.h index e4716c96af..f57388a098 100644 --- a/usr/src/uts/common/sys/lofi.h +++ b/usr/src/uts/common/sys/lofi.h @@ -23,6 +23,7 @@ * * Copyright 2013 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2016 Andrey Sokolov + * Copyright 2016 Toomas Soome */ #ifndef _SYS_LOFI_H @@ -31,12 +32,15 @@ #include #include #include -#include #include #include #include #include #include +#ifdef _KERNEL +#include +#include +#endif /* _KERNEL */ #ifdef __cplusplus extern "C" { @@ -51,6 +55,8 @@ extern "C" { #define LOFI_DRIVER_NAME "lofi" #define LOFI_CTL_NODE "ctl" #define LOFI_CTL_NAME LOFI_DRIVER_NAME LOFI_CTL_NODE +#define LOFI_BLOCK_NODE "disk" +#define LOFI_CHAR_NODE LOFI_BLOCK_NODE ",raw" #define LOFI_BLOCK_NAME LOFI_DRIVER_NAME #define LOFI_CHAR_NAME "r" LOFI_DRIVER_NAME @@ -59,6 +65,20 @@ extern "C" { #define UNCOMPRESSED 0 #define MAXALGLEN 36 +#define LOFI_CMLB_SHIFT CMLBUNIT_FORCE_P0_SHIFT +#define LOFI_PART_MASK ((1 << LOFI_CMLB_SHIFT) - 1) +#define LOFI_PART_MAX (1 << LOFI_CMLB_SHIFT) +#define LOFI_PART(x) ((x) & LOFI_PART_MASK) + +/* + * The cmlb is using its own range of minor numbers for partitions, for + * unlabeled lofi devices, we need to use another range. + */ +/* unlabeled lofi device id to minor number. */ +#define LOFI_ID2MINOR(x) ((x) << LOFI_CMLB_SHIFT) +/* lofi id from minor number. */ +#define LOFI_MINOR2ID(x) ((x) >> LOFI_CMLB_SHIFT) + /* * * Use is: @@ -127,11 +147,13 @@ typedef enum iv_method { } iv_method_t; struct lofi_ioctl { - uint32_t li_minor; + uint32_t li_id; /* lofi ID */ boolean_t li_force; boolean_t li_cleanup; boolean_t li_readonly; + boolean_t li_labeled; char li_filename[MAXPATHLEN]; + char li_devpath[MAXPATHLEN]; /* the following fields are required for compression support */ char li_algorithm[MAXALGLEN]; @@ -230,10 +252,11 @@ struct lofi_state { kcondvar_t ls_vp_cv; /* signal changes to ls_vp */ uint32_t ls_vp_iocount; /* # pending I/O requests */ boolean_t ls_vp_closereq; /* force close requested */ + boolean_t ls_vp_ready; /* is vp ready for use? */ u_offset_t ls_vp_size; - uint32_t ls_blk_open; - uint32_t ls_chr_open; - uint32_t ls_lyr_open_count; + uint32_t ls_open_lyr[LOFI_PART_MAX]; /* open count */ + uint64_t ls_open_reg[OTYPCNT]; /* bitmask */ + uint64_t ls_open_excl; /* bitmask */ int ls_openflag; boolean_t ls_cleanup; /* cleanup on close */ boolean_t ls_readonly; @@ -241,12 +264,15 @@ struct lofi_state { kstat_t *ls_kstat; kmutex_t ls_kstat_lock; struct dk_geom ls_dkg; - struct vtoc ls_vtoc; - struct dk_cinfo ls_ci; zone_ref_t ls_zone; list_node_t ls_list; /* all lofis */ + dev_info_t *ls_dip; dev_t ls_dev; /* this node's dev_t */ + cmlb_handle_t ls_cmlbhandle; + uint32_t ls_lbshift; /* logical block shift */ + uint32_t ls_pbshift; /* physical block shift */ + /* the following fields are required for compression support */ int ls_comp_algorithm_index; /* idx into compress_table */ char ls_comp_algorithm[MAXALGLEN]; @@ -280,7 +306,6 @@ struct lofi_state { iv_method_t ls_iv_type; /* for iv derivation */ kmutex_t ls_crypto_lock; crypto_ctx_template_t ls_ctx_tmpl; - }; #endif /* _KERNEL */ diff --git a/usr/src/uts/common/sys/vfs.h b/usr/src/uts/common/sys/vfs.h index 38c1fded4a..fc6e22b3a2 100644 --- a/usr/src/uts/common/sys/vfs.h +++ b/usr/src/uts/common/sys/vfs.h @@ -21,6 +21,7 @@ /* * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2016 Toomas Soome */ /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ @@ -227,7 +228,7 @@ typedef struct vfs { struct vfs *vfs_zone_prev; /* prev VFS visible in zone */ struct fem_head *vfs_femhead; /* fs monitoring */ - minor_t vfs_lofi_minor; /* minor if lofi mount */ + uint32_t vfs_lofi_id; /* ID if lofi mount */ } vfs_t; #define vfs_featureset vfs_implp->vi_featureset diff --git a/usr/src/uts/common/sys/vtoc.h b/usr/src/uts/common/sys/vtoc.h index adaf7df5b9..2bfe68ba96 100644 --- a/usr/src/uts/common/sys/vtoc.h +++ b/usr/src/uts/common/sys/vtoc.h @@ -25,6 +25,7 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2016 Toomas Soome */ @@ -272,15 +273,15 @@ struct vtoc32 { #define vtoctovtoc32(v, v32) \ { \ int i; \ - v32.v_bootinfo[0] = v.v_bootinfo[0]; \ - v32.v_bootinfo[1] = v.v_bootinfo[1]; \ - v32.v_bootinfo[2] = v.v_bootinfo[2]; \ - v32.v_sanity = v.v_sanity; \ - v32.v_version = v.v_version; \ + v32.v_bootinfo[0] = (uint32_t)v.v_bootinfo[0]; \ + v32.v_bootinfo[1] = (uint32_t)v.v_bootinfo[1]; \ + v32.v_bootinfo[2] = (uint32_t)v.v_bootinfo[2]; \ + v32.v_sanity = (uint32_t)v.v_sanity; \ + v32.v_version = (uint32_t)v.v_version; \ bcopy(v.v_volume, v32.v_volume, LEN_DKL_VVOL); \ v32.v_sectorsz = v.v_sectorsz; \ v32.v_nparts = v.v_nparts; \ - v32.v_version = v.v_version; \ + v32.v_version = (uint32_t)v.v_version; \ for (i = 0; i < 10; i++) \ v32.v_reserved[i] = v.v_reserved[i]; \ for (i = 0; i < V_NUMPAR; i++) { \ diff --git a/usr/src/uts/intel/lofi/Makefile b/usr/src/uts/intel/lofi/Makefile index deef4ab1b2..13b0bef650 100644 --- a/usr/src/uts/intel/lofi/Makefile +++ b/usr/src/uts/intel/lofi/Makefile @@ -18,7 +18,7 @@ # # CDDL HEADER END # -# +# Copyright 2016 Toomas Soome # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -58,6 +58,8 @@ ALL_TARGET = $(BINARY) $(SRC_CONFILE) LINT_TARGET = $(MODULE).lint INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) +LDFLAGS += -dy -Nmisc/cmlb + # # Default build targets. # diff --git a/usr/src/uts/sparc/lofi/Makefile b/usr/src/uts/sparc/lofi/Makefile index 9a98791817..3b9a1e5703 100644 --- a/usr/src/uts/sparc/lofi/Makefile +++ b/usr/src/uts/sparc/lofi/Makefile @@ -18,7 +18,7 @@ # # CDDL HEADER END # -# +# Copyright 2016 Toomas Soome # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -51,6 +51,8 @@ ALL_TARGET = $(BINARY) $(SRC_CONFILE) LINT_TARGET = $(MODULE).lint INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) +LDFLAGS += -dy -Nmisc/cmlb + # # Overrides. # -- 2.11.4.GIT