diff options
| author | Jerry Jelinek <jerry.jelinek@joyent.com> | 2016-02-24 20:20:29 +0000 |
|---|---|---|
| committer | Jerry Jelinek <jerry.jelinek@joyent.com> | 2016-02-24 20:20:29 +0000 |
| commit | bc1a14d6a4bd455f488d3ec4bcaf421a9b9f2f55 (patch) | |
| tree | c8a9cc183a28dee47fb7aa9c092723f6151152b0 /usr/src | |
| parent | d3d31ab6f2a28d67593b8dcad42c0f03964ab6c0 (diff) | |
| download | illumos-joyent-bc1a14d6a4bd455f488d3ec4bcaf421a9b9f2f55.tar.gz | |
OS-4614 lx want /sys/block emulation
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Diffstat (limited to 'usr/src')
| -rw-r--r-- | usr/src/uts/common/brand/lx/sysfs/lx_sysfs.h | 2 | ||||
| -rw-r--r-- | usr/src/uts/common/brand/lx/sysfs/lx_sysvfsops.c | 11 | ||||
| -rw-r--r-- | usr/src/uts/common/brand/lx/sysfs/lx_sysvnops.c | 489 | ||||
| -rw-r--r-- | usr/src/uts/intel/lx_sysfs/Makefile | 5 |
4 files changed, 490 insertions, 17 deletions
diff --git a/usr/src/uts/common/brand/lx/sysfs/lx_sysfs.h b/usr/src/uts/common/brand/lx/sysfs/lx_sysfs.h index e46dc0496d..17d3a99d36 100644 --- a/usr/src/uts/common/brand/lx/sysfs/lx_sysfs.h +++ b/usr/src/uts/common/brand/lx/sysfs/lx_sysfs.h @@ -100,6 +100,7 @@ typedef enum lxsys_nodetype { LXSYS_DEVICES_NET, /* /sys/devices/virtual/net/<iface> */ LXSYS_BLOCK, /* /sys/block/<dev> */ LXSYS_DEVICES_BDI, /* /sys/devices/virtual/bdi/<dev> */ + LXSYS_DEVICES_ZFS, /* /sys/devices/zfs/<dev> */ LXSYS_MAXTYPE, /* type limit */ } lxsys_nodetype_t; @@ -142,6 +143,7 @@ struct lxsys_node { * which is attached to vfs_data in the vfs structure */ typedef struct lxsys_mnt { + ldi_ident_t lxsysm_li; /* set once at mount time */ kmutex_t lxsysm_lock; /* protects fields */ lxsys_node_t *lxsysm_node; /* node at root of sys mount */ zone_t *lxsysm_zone; /* zone for this mount */ diff --git a/usr/src/uts/common/brand/lx/sysfs/lx_sysvfsops.c b/usr/src/uts/common/brand/lx/sysfs/lx_sysvfsops.c index c33e61345e..944703296a 100644 --- a/usr/src/uts/common/brand/lx/sysfs/lx_sysvfsops.c +++ b/usr/src/uts/common/brand/lx/sysfs/lx_sysvfsops.c @@ -10,7 +10,7 @@ */ /* - * Copyright 2015 Joyent, Inc. + * Copyright 2016 Joyent, Inc. */ /* @@ -181,6 +181,8 @@ lxsys_mount(vfs_t *vfsp, vnode_t *mvp, mounta_t *uap, cred_t *cr) { lxsys_mnt_t *lxsys_mnt; zone_t *zone = curproc->p_zone; + ldi_ident_t li; + int err; /* * must be root to mount @@ -210,6 +212,13 @@ lxsys_mount(vfs_t *vfsp, vnode_t *mvp, mounta_t *uap, cred_t *cr) lxsys_mnt = kmem_alloc(sizeof (*lxsys_mnt), KM_SLEEP); + if ((err = ldi_ident_from_mod(&modlinkage, &li)) != 0) { + kmem_free(lxsys_mnt, sizeof (*lxsys_mnt)); + return (err); + } + + lxsys_mnt->lxsysm_li = li; + mutex_enter(&lxsys_mount_lock); /* diff --git a/usr/src/uts/common/brand/lx/sysfs/lx_sysvnops.c b/usr/src/uts/common/brand/lx/sysfs/lx_sysvnops.c index 70cf0635c7..7111d56c37 100644 --- a/usr/src/uts/common/brand/lx/sysfs/lx_sysvnops.c +++ b/usr/src/uts/common/brand/lx/sysfs/lx_sysvnops.c @@ -43,6 +43,7 @@ #include <sys/ethernet.h> #include <inet/ip_arp.h> #include <sys/kstat.h> +#include <sys/zfs_ioctl.h> #include "lx_sysfs.h" @@ -74,18 +75,26 @@ static vnode_t *lxsys_lookup_class_netdir(lxsys_node_t *, char *); static vnode_t *lxsys_lookup_devices_virtual_netdir(lxsys_node_t *, char *); static vnode_t *lxsys_lookup_blockdir(lxsys_node_t *, char *); static vnode_t *lxsys_lookup_devices_virtual_bdidir(lxsys_node_t *, char *); +static vnode_t *lxsys_lookup_devices_zfsdir(lxsys_node_t *, char *); static int lxsys_read_devices_virtual_net(lxsys_node_t *, lxsys_uiobuf_t *); +static int lxsys_read_devices_zfs_block(lxsys_node_t *, lxsys_uiobuf_t *); static int lxsys_readdir_static(lxsys_node_t *, uio_t *, int *); static int lxsys_readdir_class_netdir(lxsys_node_t *, uio_t *, int *); static int lxsys_readdir_devices_virtual_netdir(lxsys_node_t *, uio_t *, int *); static int lxsys_readdir_blockdir(lxsys_node_t *, uio_t *, int *); static int lxsys_readdir_devices_virtual_bdidir(lxsys_node_t *, uio_t *, int *); +static int lxsys_readdir_devices_zfsdir(lxsys_node_t *, uio_t *, int *); static int lxsys_readlink_class_net(lxsys_node_t *, char *, size_t); static int lxsys_readlink_block(lxsys_node_t *, char *, size_t); +static void lxsys_zfs_list_zvols(ldi_ident_t, list_t *); + +extern int zvol_name2minor(const char *, minor_t *); +extern int zvol_create_minor(const char *); + /* * The lx /sys vnode operations vector */ @@ -119,6 +128,7 @@ const fs_operation_def_t lxsys_vnodeops_template[] = { * 3 - SYS_DEVICES_NET * 4 - SYS_BLOCK * 5 - SYS_DEVICES_BDI + * 6 - SYS_DEVICES_ZFS * * Static entries will have assigned INSTANCE identifiers: * - 0x00: /sys @@ -132,6 +142,7 @@ const fs_operation_def_t lxsys_vnodeops_template[] = { * - 0x08: /sys/devices/virtual/net * - 0x09: /sys/block * - 0x0a: /sys/devices/virtual/bdi + * - 0x0b: /sys/devices/zfs * * Dynamic /sys/class/net/<interface> symlinks will use an INSTANCE derived * from the corresonding ifindex. @@ -140,9 +151,14 @@ const fs_operation_def_t lxsys_vnodeops_template[] = { * an INSTANCE derived from the ifindex and statically assigned ENDPOINT IDs * for the contained entries. * - * Dynamic /sys/block/<dev> symlinks and /sys/devices/virtual/bdi/<dev> - * directories will use an INSTANCE derived from the device major and instance - * from records listed in kstat. + * Dynamic /sys/block/<dev> symlinks will use an INSTANCE derived from the + * device major and instance from records listed in kstat or zvols. + * + * Dynamic /sys/devices/virtual/bdi/<dev> directories will use an INSTANCE + * derived from the device major and instance from records listed in kstat. + * + * Dynamic /sys/devices/zfs/<dev> directories will use an INSTANCE derived from + * the zvols. */ #define LXSYS_INST_CLASSDIR 0x1 @@ -155,6 +171,7 @@ const fs_operation_def_t lxsys_vnodeops_template[] = { #define LXSYS_INST_DEVICES_VIRTUAL_NETDIR 0x8 #define LXSYS_INST_BLOCKDIR 0x9 #define LXSYS_INST_DEVICES_VIRTUAL_BDIDIR 0xa +#define LXSYS_INST_DEVICES_ZFSDIR 0xb /* * file contents of an lx /sys directory. @@ -174,7 +191,8 @@ static lxsys_dirent_t dirlist_fs[] = { }; static lxsys_dirent_t dirlist_devices[] = { { LXSYS_INST_DEVICES_SYSTEMDIR, "system" }, - { LXSYS_INST_DEVICES_VIRTUALDIR, "virtual" } + { LXSYS_INST_DEVICES_VIRTUALDIR, "virtual" }, + { LXSYS_INST_DEVICES_ZFSDIR, "zfs" } }; static lxsys_dirent_t dirlist_devices_virtual[] = { { LXSYS_INST_DEVICES_VIRTUAL_BDIDIR, "bdi" }, @@ -190,6 +208,8 @@ static lxsys_dirent_t dirlist_devices_virtual[] = { #define LXSYS_ENDP_NET_TXQLEN 6 #define LXSYS_ENDP_NET_TYPE 7 +#define LXSYS_ENDP_BLOCK_DEVICE 1 + static lxsys_dirent_t dirlist_devices_virtual_net[] = { { LXSYS_ENDP_NET_ADDRESS, "address" }, { LXSYS_ENDP_NET_ADDRLEN, "addr_len" }, @@ -200,6 +220,10 @@ static lxsys_dirent_t dirlist_devices_virtual_net[] = { { LXSYS_ENDP_NET_TYPE, "type" } }; +static lxsys_dirent_t dirlist_devices_zfs_block[] = { + { LXSYS_ENDP_BLOCK_DEVICE, "device" } +}; + #define SYSDIRLISTSZ(l) (sizeof (l) / sizeof ((l)[0])) #define SYSDLENT(i, l) { i, l, SYSDIRLISTSZ(l) } @@ -224,6 +248,7 @@ static vnode_t *(*lxsys_lookup_function[LXSYS_MAXTYPE])() = { lxsys_lookup_devices_virtual_netdir, /* LXSYS_DEVICES_NET */ lxsys_lookup_blockdir, /* LXSYS_BLOCK */ lxsys_lookup_devices_virtual_bdidir, /* LXSYS_DEVICES_BDI */ + lxsys_lookup_devices_zfsdir, /* LXSYS_DEVICES_ZFS */ }; /* @@ -236,6 +261,7 @@ static int (*lxsys_readdir_function[LXSYS_MAXTYPE])() = { lxsys_readdir_devices_virtual_netdir, /* LXSYS_DEVICES_NET */ lxsys_readdir_blockdir, /* LXSYS_BLOCK */ lxsys_readdir_devices_virtual_bdidir, /* LXSYS_DEVICES_BDI */ + lxsys_readdir_devices_zfsdir, /* LXSYS_DEVICES_ZFS */ }; /* @@ -248,6 +274,7 @@ static int (*lxsys_read_function[LXSYS_MAXTYPE])() = { lxsys_read_devices_virtual_net, /* LXSYS_DEVICES_NET */ NULL, /* LXSYS_BLOCK */ NULL, /* LXSYS_DEVICES_BDI */ + lxsys_read_devices_zfs_block, /* LXSYS_DEVICES_ZFS */ }; /* @@ -260,8 +287,14 @@ static int (*lxsys_readlink_function[LXSYS_MAXTYPE])() = { NULL, /* LXSYS_DEVICES_NET */ lxsys_readlink_block, /* LXSYS_BLOCK */ NULL, /* LXSYS_DEVICES_BDI */ + NULL, /* LXSYS_DEVICES_ZFS */ }; +typedef struct lxsys_zfs_ds { + list_node_t ds_link; + char ds_name[MAXPATHLEN]; + uint64_t ds_cookie; +} lxsys_zfs_ds_t; /* * Utility functions @@ -351,13 +384,42 @@ lxsys_disk_instance(kstat_t *ksp) * Use a naive method to generate the 16-bit disk instance number for * calculating the inode. This is adequate when module and disk counts * remain low. + * + * The high order bit in the 2nd byte indicates a zvol. */ - result = (mod_name_to_major(ksp->ks_module) & 0xff) << 8; + result = (mod_name_to_major(ksp->ks_module) & 0x7f) << 8; result |= (ksp->ks_instance & 0xff); return (result); } +static int +lxsys_zvol_instance(char *znm) +{ + int result; + minor_t m; + /* + * Use a naive method to generate the 16-bit disk instance number for + * calculating the inode. This is adequate when zvol counts remain low + * (< 32k). + * + * The high order bit in the 2nd byte indicates a zvol. + */ + result = 0x80 << 8; + + /* + * zvol_name2minor simplifies things here but the call won't succeed + * unless the minor has first been created, so we can't count on this. + */ + if (zvol_name2minor(znm, &m) != 0) { + (void) zvol_create_minor(znm); + if (zvol_name2minor(znm, &m) != 0) + return (0); + } + + result |= (m & 0xffff); + return (result); +} /* * lxsys_open(): Vnode operation for VOP_OPEN() @@ -530,6 +592,41 @@ lxsys_lookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pathp, return ((*vpp == NULL) ? ENOENT : 0); } +/* zvol basename to flatten namespace */ +static char * +lxsys_zv_basename(char *ds_name) +{ + char *nm; + + if ((nm = strrchr(ds_name, '/')) != NULL) { + nm++; + ASSERT(*nm != '\0'); + } else { + nm = ds_name; + } + + return (nm); +} + +/* Cleanup zvol list */ +static int +lxsys_zvol_cleanup(list_t *zvol_lst) +{ + lxsys_zfs_ds_t *zv; + int fnd = 0; + + zv = list_remove_head(zvol_lst); + while (zv != NULL) { + fnd = 1; + kmem_free(zv, sizeof (lxsys_zfs_ds_t)); + zv = list_remove_head(zvol_lst); + } + + list_destroy(zvol_lst); + + return (fnd); +} + static lxsys_node_t * lxsys_lookup_disk(lxsys_node_t *ldp, char *comp, lxsys_nodetype_t type) { @@ -537,6 +634,10 @@ lxsys_lookup_disk(lxsys_node_t *ldp, char *comp, lxsys_nodetype_t type) int nidx, i; size_t sidx; lxsys_node_t *lnp = NULL; + int inst; + ldi_ident_t li = VTOLXSM(LXSTOV(ldp))->lxsysm_li; + list_t zvol_lst; + lxsys_zfs_ds_t *zv; ks0.ks_kid = 0; ksr = (kstat_t *)lxsys_kstat_read(&ks0, B_FALSE, &sidx, &nidx); @@ -545,7 +646,6 @@ lxsys_lookup_disk(lxsys_node_t *ldp, char *comp, lxsys_nodetype_t type) } for (i = 1; i < nidx; i++) { kstat_t *ksp = &ksr[i]; - int inst; if (ksp->ks_type != KSTAT_TYPE_IO || strcmp(ksp->ks_class, "disk") != 0) { @@ -558,6 +658,33 @@ lxsys_lookup_disk(lxsys_node_t *ldp, char *comp, lxsys_nodetype_t type) } } kmem_free(ksr, sidx); + + if (lnp != NULL) + return (lnp); + + /* try a zvol */ + list_create(&zvol_lst, sizeof (lxsys_zfs_ds_t), + offsetof(lxsys_zfs_ds_t, ds_link)); + + lxsys_zfs_list_zvols(li, &zvol_lst); + + zv = list_remove_head(&zvol_lst); + while (zv != NULL) { + char *nm = lxsys_zv_basename(zv->ds_name); + + if (strcmp(nm, comp) == 0 && + (inst = lxsys_zvol_instance(zv->ds_name)) != 0) { + lnp = lxsys_getnode(ldp->lxsys_vnode, type, inst, 0); + kmem_free(zv, sizeof (lxsys_zfs_ds_t)); + break; + } + + kmem_free(zv, sizeof (lxsys_zfs_ds_t)); + zv = list_remove_head(&zvol_lst); + } + + (void) lxsys_zvol_cleanup(&zvol_lst); + return (lnp); } @@ -597,6 +724,9 @@ lxsys_lookup_static(lxsys_node_t *ldp, char *comp) case LXSYS_INST_DEVICES_VIRTUAL_BDIDIR: node_type = LXSYS_DEVICES_BDI; break; + case LXSYS_INST_DEVICES_ZFSDIR: + node_type = LXSYS_DEVICES_ZFS; + break; default: /* Another static node */ node_instance = dirent[i].d_idnum; @@ -747,6 +877,44 @@ lxsys_lookup_devices_virtual_bdidir(lxsys_node_t *ldp, char *comp) return (NULL); } +static vnode_t * +lxsys_lookup_devices_zfsdir(lxsys_node_t *ldp, char *comp) +{ + lxsys_node_t *lnp; + + if (ldp->lxsys_instance == 0) { + /* top-level dev listing */ + lnp = lxsys_lookup_disk(ldp, comp, LXSYS_DEVICES_ZFS); + + if (lnp != NULL) { + return (lnp->lxsys_vnode); + } + } else if (ldp->lxsys_endpoint == 0) { + /* disk-level sub-item listing */ + int i, size; + lxsys_dirent_t *dirent; + + /* + * All of these entries currently look like regular files + * but on a real Linux system some will be subdirs. This should + * be fixed when we populate the directory for real. + */ + size = SYSDIRLISTSZ(dirlist_devices_zfs_block); + for (i = 0; i < size; i++) { + dirent = &dirlist_devices_zfs_block[i]; + if (strncmp(comp, dirent->d_name, LXSNSIZ) == 0) { + lnp = lxsys_getnode(ldp->lxsys_vnode, + ldp->lxsys_type, ldp->lxsys_instance, + dirent->d_idnum); + lnp->lxsys_vnode->v_type = VREG; + lnp->lxsys_mode = 0444; + return (lnp->lxsys_vnode); + } + } + } + + return (NULL); +} static int lxsys_read_devices_virtual_net(lxsys_node_t *lnp, lxsys_uiobuf_t *luio) @@ -821,6 +989,17 @@ lxsys_read_devices_virtual_net(lxsys_node_t *lnp, lxsys_uiobuf_t *luio) return (error); } +static int +lxsys_read_devices_zfs_block(lxsys_node_t *lnp, lxsys_uiobuf_t *luio) +{ + uint_t dskindex = lnp->lxsys_instance; + + if (dskindex == 0 || lnp->lxsys_endpoint == 0) { + return (EISDIR); + } + + return (EIO); +} /* * lxsys_readdir(): Vnode operation for VOP_READDIR() */ @@ -1121,6 +1300,156 @@ lxsys_readdir_ifaces(lxsys_node_t *ldp, struct uio *uiop, int *eofp, } static int +lxsys_zfs_ioctl(ldi_handle_t lh, int cmd, zfs_cmd_t *zc, size_t *dst_alloc_size) +{ + uint64_t cookie; + size_t dstsize = 8192; + int rc, unused; + + cookie = zc->zc_cookie; + +again: + zc->zc_nvlist_dst = (uint64_t)(intptr_t)kmem_alloc(dstsize, KM_SLEEP); + zc->zc_nvlist_dst_size = dstsize; + + rc = ldi_ioctl(lh, cmd, (intptr_t)zc, FKIOCTL, kcred, &unused); + if (rc == ENOMEM) { + /* + * Our nvlist_dst buffer was too small, retry with a bigger + * buffer. ZFS will tell us the exact needed size. + */ + size_t newsize = zc->zc_nvlist_dst_size; + ASSERT(newsize > dstsize); + + kmem_free((void *)(uintptr_t)zc->zc_nvlist_dst, dstsize); + dstsize = newsize; + zc->zc_cookie = cookie; + + goto again; + } + + if (dst_alloc_size != NULL) { + *dst_alloc_size = dstsize; + } else { + /* Caller didn't want the nvlist_dst anyway */ + kmem_free((void *)(uintptr_t)zc->zc_nvlist_dst, dstsize); + zc->zc_nvlist_dst = NULL; + } + + return (rc); +} + +static void +lxsys_zfs_list_zvols(ldi_ident_t li, list_t *zvol_lst) +{ + int rc; + size_t size; + ldi_handle_t lh; + dev_t zfs_dv; + zfs_cmd_t *zc; + nvpair_t *elem = NULL; + nvlist_t *pnv = NULL; + list_t ds_lst; + + if (ldi_open_by_name("/dev/zfs", FREAD | FWRITE, kcred, &lh, li) != 0) + return; + + if (ldi_get_dev(lh, &zfs_dv) != 0) { + ldi_close(lh, FREAD|FWRITE, kcred); + return; + } + + zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); + bzero(zc, sizeof (zfs_cmd_t)); + + rc = lxsys_zfs_ioctl(lh, ZFS_IOC_POOL_CONFIGS, zc, &size); + if (rc != 0) + goto out; + + ASSERT(zc->zc_cookie > 0); + + rc = nvlist_unpack((char *)(uintptr_t)zc->zc_nvlist_dst, + zc->zc_nvlist_dst_size, &pnv, 0); + + kmem_free((void *)(uintptr_t)zc->zc_nvlist_dst, size); + + if (rc != 0) + goto out; + + /* + * We use a dataset list to process all of the datasets in the pool + * without doing recursion so that we don't risk blowing the kernel + * stack. + */ + list_create(&ds_lst, sizeof (lxsys_zfs_ds_t), + offsetof(lxsys_zfs_ds_t, ds_link)); + + while ((elem = nvlist_next_nvpair(pnv, elem)) != NULL) { + lxsys_zfs_ds_t *ds; + + ds = kmem_zalloc(sizeof (lxsys_zfs_ds_t), KM_SLEEP); + (void) strcpy(ds->ds_name, nvpair_name(elem)); + + list_insert_head(&ds_lst, ds); + + while (ds != NULL) { + bzero(zc, sizeof (zfs_cmd_t)); + zc->zc_cookie = ds->ds_cookie; + (void) strcpy(zc->zc_name, ds->ds_name); + + rc = lxsys_zfs_ioctl(lh, ZFS_IOC_DATASET_LIST_NEXT, zc, + NULL); + + /* Update the cookie before doing anything else. */ + ds->ds_cookie = zc->zc_cookie; + + if (rc != 0) { + list_remove(&ds_lst, ds); + kmem_free(ds, sizeof (lxsys_zfs_ds_t)); + ds = list_tail(&ds_lst); + continue; + } + + /* Reserved internal names, skip over these. */ + if (strchr(zc->zc_name, '$') != NULL || + strchr(zc->zc_name, '%') != NULL) + continue; + + if (zc->zc_objset_stats.dds_type == DMU_OST_ZVOL) { + /* add it to the zvol list */ + lxsys_zfs_ds_t *zv; + + zv = kmem_zalloc(sizeof (lxsys_zfs_ds_t), + KM_SLEEP); + (void) strcpy(zv->ds_name, zc->zc_name); + list_insert_tail(zvol_lst, zv); + } else { + lxsys_zfs_ds_t *nds; + + /* Create a new ds_t for the child. */ + nds = kmem_zalloc(sizeof (lxsys_zfs_ds_t), + KM_SLEEP); + (void) strcpy(nds->ds_name, zc->zc_name); + list_insert_after(&ds_lst, ds, nds); + + /* Depth-first, so do the one just created. */ + ds = nds; + } + } + + ASSERT(list_is_empty(&ds_lst)); + } + + ASSERT(list_is_empty(&ds_lst)); + list_destroy(&ds_lst); + +out: + nvlist_free(pnv); + ldi_close(lh, FREAD|FWRITE, kcred); + kmem_free(zc, sizeof (zfs_cmd_t)); +} + +static int lxsys_readdir_disks(lxsys_node_t *ldp, struct uio *uiop, int *eofp, lxsys_nodetype_t type) { @@ -1130,6 +1459,12 @@ lxsys_readdir_disks(lxsys_node_t *ldp, struct uio *uiop, int *eofp, kstat_t ks0, *ksr; int nidx, i, skip, error; size_t sidx; + int reclen; + uint_t instance; + ldi_ident_t li = VTOLXSM(LXSTOV(ldp))->lxsysm_li; + list_t zvol_lst; + lxsys_zfs_ds_t *zv; + boolean_t zv_done; /* Emit "." and ".." entries */ oresid = uiop->uio_resid; @@ -1138,17 +1473,25 @@ lxsys_readdir_disks(lxsys_node_t *ldp, struct uio *uiop, int *eofp, return (error); } + skip = (uiop->uio_offset/LXSYS_SDSIZE) - 2; + i = nidx = 0; + + /* + * We show all disks (virtual and physical) for LXSYS_BLOCK, only + * virtual disks for LXSYS_DEVICES_BDI and only physical disks for + * LXSYS_DEVICES_ZFS. + */ + if (type == LXSYS_DEVICES_ZFS) + goto zvols; + ks0.ks_kid = 0; ksr = (kstat_t *)lxsys_kstat_read(&ks0, B_FALSE, &sidx, &nidx); if (ksr == NULL) { *eofp = 1; return (0); } - skip = (uiop->uio_offset/LXSYS_SDSIZE) - 2; for (i = 1; i < nidx; i++) { kstat_t *ksp = &ksr[i]; - uint_t instance; - int reclen; if (ksp->ks_type != KSTAT_TYPE_IO || strcmp(ksp->ks_class, "disk") != 0) { @@ -1179,11 +1522,72 @@ lxsys_readdir_disks(lxsys_node_t *ldp, struct uio *uiop, int *eofp, } } - /* Indicate EOF if we reached the end of the kstats. */ - if (i >= nidx) { + kmem_free(ksr, sidx); + +zvols: + zv_done = B_TRUE; + if (type == LXSYS_DEVICES_BDI) + goto done; + + list_create(&zvol_lst, sizeof (lxsys_zfs_ds_t), + offsetof(lxsys_zfs_ds_t, ds_link)); + + lxsys_zfs_list_zvols(li, &zvol_lst); + + zv = list_remove_head(&zvol_lst); + while (zv != NULL) { + char *nm; + + if (skip > 0) { + skip--; + kmem_free(zv, sizeof (lxsys_zfs_ds_t)); + zv = list_remove_head(&zvol_lst); + continue; + } + + nm = lxsys_zv_basename(zv->ds_name); + if (strlen(nm) > LXSNSIZ) { + kmem_free(zv, sizeof (lxsys_zfs_ds_t)); + zv = list_remove_head(&zvol_lst); + continue; + } + + (void) strncpy(dirent->d_name, nm, LXSNSIZ); + instance = lxsys_zvol_instance(zv->ds_name); + if (instance == 0) { + kmem_free(zv, sizeof (lxsys_zfs_ds_t)); + zv = list_remove_head(&zvol_lst); + continue; + } + + kmem_free(zv, sizeof (lxsys_zfs_ds_t)); + + dirent->d_ino = lxsys_inode(type, instance, 0); + reclen = DIRENT64_RECLEN(strlen(dirent->d_name)); + + uresid = uiop->uio_resid; + if (reclen > uresid) { + if (uresid == oresid) { + /* Not enough space for one record */ + error = EINVAL; + } + break; + } + if ((error = lxsys_dirent_out(dirent, reclen, uiop)) != 0) { + break; + } + + zv = list_remove_head(&zvol_lst); + } + + if (lxsys_zvol_cleanup(&zvol_lst) != 0) + zv_done = B_FALSE; /* we didn't process all of them */ + +done: + /* Indicate EOF if we reached the end of the kstats and zvols. */ + if (i >= nidx && zv_done) { *eofp = 1; } - kmem_free(ksr, sidx); return (error); } @@ -1272,7 +1676,7 @@ lxsys_readdir_devices_virtual_bdidir(lxsys_node_t *lnp, uio_t *uiop, int *eofp) if (lnp->lxsys_instance == 0) { /* top-level dev listing */ error = lxsys_readdir_disks(lnp, uiop, eofp, - LXSYS_DEVICES_NET); + LXSYS_DEVICES_BDI); } else if (lnp->lxsys_endpoint == 0) { /* disk-level sub-item listing (empty for now) */ error = lxsys_readdir_subdir(lnp, uiop, eofp, NULL, 0); @@ -1284,6 +1688,32 @@ lxsys_readdir_devices_virtual_bdidir(lxsys_node_t *lnp, uio_t *uiop, int *eofp) return (error); } +static int +lxsys_readdir_devices_zfsdir(lxsys_node_t *lnp, uio_t *uiop, int *eofp) +{ + int error; + + if (lnp->lxsys_instance == 0) { + /* top-level dev listing */ + error = lxsys_readdir_disks(lnp, uiop, eofp, + LXSYS_DEVICES_ZFS); + } else if (lnp->lxsys_endpoint == 0) { + /* disk-level sub-item listing */ + error = lxsys_readdir_subdir(lnp, uiop, eofp, + dirlist_devices_zfs_block, + SYSDIRLISTSZ(dirlist_devices_zfs_block)); + } else { + /* + * Currently there shouldn't be subdirs below this but + * on a real Linux system some will be subdirs. This should + * be fixed when we populate the directory for real. + */ + error = ENOTDIR; + } + + return (error); +} + /* * lxsys_readlink(): Vnode operation for VOP_READLINK() */ @@ -1359,6 +1789,9 @@ lxsys_readlink_block(lxsys_node_t *lnp, char *buf, size_t len) kstat_t ks0; int nidx, i, inst, error = EINVAL; size_t sidx; + ldi_ident_t li = VTOLXSM(LXSTOV(lnp))->lxsysm_li; + list_t zvol_lst; + lxsys_zfs_ds_t *zv; if ((inst = lnp->lxsys_instance) == 0) { return (error); @@ -1378,12 +1811,40 @@ lxsys_readlink_block(lxsys_node_t *lnp, char *buf, size_t len) } if (lxsys_disk_instance(ksp) == inst) { (void) snprintf(buf, len, - "/sys/devices/virtual/bdi/%s", ksp->ks_name); + "../devices/virtual/bdi/%s", ksp->ks_name); error = 0; break; } } kmem_free(ksr, sidx); + + if (error == 0) + return (0); + + /* try a zvol */ + list_create(&zvol_lst, sizeof (lxsys_zfs_ds_t), + offsetof(lxsys_zfs_ds_t, ds_link)); + + lxsys_zfs_list_zvols(li, &zvol_lst); + + zv = list_remove_head(&zvol_lst); + while (zv != NULL) { + if (lxsys_zvol_instance(zv->ds_name) == inst) { + char *nm = lxsys_zv_basename(zv->ds_name); + + (void) snprintf(buf, len, + "../devices/zfs/%s", nm); + error = 0; + kmem_free(zv, sizeof (lxsys_zfs_ds_t)); + break; + } + + kmem_free(zv, sizeof (lxsys_zfs_ds_t)); + zv = list_remove_head(&zvol_lst); + } + + (void) lxsys_zvol_cleanup(&zvol_lst); + return (error); } diff --git a/usr/src/uts/intel/lx_sysfs/Makefile b/usr/src/uts/intel/lx_sysfs/Makefile index 10f5344d46..01c99a2348 100644 --- a/usr/src/uts/intel/lx_sysfs/Makefile +++ b/usr/src/uts/intel/lx_sysfs/Makefile @@ -10,7 +10,7 @@ # # -# Copyright 2015 Joyent, Inc. +# Copyright 2016 Joyent, Inc. # UTSBASE = ../.. @@ -23,6 +23,7 @@ LINTS = $(LX_SYS_OBJS:%.o=$(LINTS_DIR)/%.ln) ROOTMODULE = $(USR_FS_DIR)/$(MODULE) INC_PATH += -I$(UTSBASE)/common/brand/lx -I$(LX_CMN) +INC_PATH += -I$(UTSBASE)/common/fs/zfs include $(UTSBASE)/intel/Makefile.intel @@ -32,7 +33,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) CFLAGS += $(CCVERBOSE) -LDFLAGS += -dy -Nbrand/lx_brand -Ndrv/ip +LDFLAGS += -dy -Nbrand/lx_brand -Ndrv/ip -Nfs/zfs # # For now, disable these lint checks; maintainers should endeavor |
