summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Wilsdon <jwilsdon@joyent.com>2016-02-21 07:38:52 +0000
committerJosh Wilsdon <jwilsdon@joyent.com>2016-02-21 07:38:52 +0000
commit038ce5502796a7e9220ec1716eb409242250bf09 (patch)
tree1b847955e9e5d4ba569c9b1034be4bd0cba45781
parentbfa0d80e3f03620084e3bc6c18283b5c87b89839 (diff)
parent74b22239b3d05923a5c08d00fc5d82a3fa7d273b (diff)
downloadillumos-joyent-OS-4903.tar.gz
Merge branch 'master' into OS-4903OS-4903
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/mount_nfs.c38
-rw-r--r--usr/src/uts/common/brand/lx/procfs/lx_prvnops.c24
-rw-r--r--usr/src/uts/common/brand/lx/sysfs/lx_sysfs.h4
-rw-r--r--usr/src/uts/common/brand/lx/sysfs/lx_sysvnops.c370
-rw-r--r--usr/src/uts/common/fs/ufs/ufs_subr.c2
-rw-r--r--usr/src/uts/common/inet/ip/conn_opt.c20
-rw-r--r--usr/src/uts/common/inet/tcp/tcp_opt_data.c6
-rw-r--r--usr/src/uts/sun4u/cpu/common_asm.s39
-rw-r--r--usr/src/uts/sun4v/cpu/common_asm.s39
9 files changed, 504 insertions, 38 deletions
diff --git a/usr/src/lib/brand/lx/lx_brand/common/mount_nfs.c b/usr/src/lib/brand/lx/lx_brand/common/mount_nfs.c
index 5bfb2cdaa0..54ce9f6f53 100644
--- a/usr/src/lib/brand/lx/lx_brand/common/mount_nfs.c
+++ b/usr/src/lib/brand/lx/lx_brand/common/mount_nfs.c
@@ -96,6 +96,7 @@
#define RET_OK 0
#define RET_RETRY 32
#define RET_ERR 33
+#define RET_PROTOUNSUPP 34
#define RET_MNTERR 1000
#define ERR_PROTO_NONE 0
#define ERR_PROTO_INVALID 901
@@ -110,8 +111,10 @@ typedef struct err_ret {
} err_ret_t;
#define SET_ERR_RET(errst, etype, eval) \
+ { \
(errst)->error_type = etype; \
- (errst)->error_value = eval;
+ (errst)->error_value = eval; \
+ }
/*
* Built-in netconfig table.
@@ -413,6 +416,8 @@ mount_nfs(struct mnttab *mntp, int mntflags, err_ret_t *retry_error,
/* All attempts failed */
if (r == RET_MNTERR) {
r = -EREMOTE;
+ } else if (r == RET_PROTOUNSUPP) {
+ r = -EPROTONOSUPPORT;
} else if (r != RET_RETRY) {
r = -EAGAIN;
}
@@ -1406,14 +1411,16 @@ get_addr(char *hostname, rpcprog_t prog, rpcvers_t vers,
/* nb is NULL - deal with errors */
if (error) {
- if (error->error_type == ERR_NOHOST)
+ if (error->error_type == ERR_NOHOST) {
SET_ERR_RET(&errsave_nohost,
error->error_type,
error->error_value);
- if (error->error_type == ERR_RPCERROR)
+ }
+ if (error->error_type == ERR_RPCERROR) {
SET_ERR_RET(&errsave_rpcerr,
error->error_type,
error->error_value);
+ }
}
/* continue with same protocol selection */
@@ -1447,15 +1454,17 @@ retry:
/* nb is NULL - deal with errors */
if (error) {
- if (error->error_type == ERR_NOHOST)
+ if (error->error_type == ERR_NOHOST) {
SET_ERR_RET(&errsave_nohost,
error->error_type,
error->error_value);
+ }
- if (error->error_type == ERR_RPCERROR)
+ if (error->error_type == ERR_RPCERROR) {
SET_ERR_RET(&errsave_rpcerr,
error->error_type,
error->error_value);
+ }
}
/*
@@ -1487,16 +1496,18 @@ retry:
done:
if (nb == NULL) {
/*
- * Check the saved errors. The RPC error has *
+ * Check the saved errors. The RPC error has
* precedence over the no host error.
*/
- if (errsave_nohost.error_type != ERR_PROTO_NONE)
+ if (errsave_nohost.error_type != ERR_PROTO_NONE) {
SET_ERR_RET(error, errsave_nohost.error_type,
errsave_nohost.error_value);
+ }
- if (errsave_rpcerr.error_type != ERR_PROTO_NONE)
+ if (errsave_rpcerr.error_type != ERR_PROTO_NONE) {
SET_ERR_RET(error, errsave_rpcerr.error_type,
errsave_rpcerr.error_value);
+ }
}
return (nb);
@@ -1607,6 +1618,17 @@ get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp,
}
nmdp->nmd_nfsvers_to_use = savevers;
+ if (retval == RET_ERR && error.error_type == ERR_RPCERROR &&
+ error.error_value == RPC_PROGVERSMISMATCH &&
+ nmdp->nmd_nfsvers != 0) {
+ /*
+ * We had an explicit vers=N mount request which locked
+ * us in to that version, however the server does not
+ * support that version (and responded to tell us that).
+ */
+ return (RET_PROTOUNSUPP);
+ }
+
vers_to_try--;
/* If no more versions to try, let the user know. */
if (vers_to_try < vers_min)
diff --git a/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c b/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c
index 2911a182df..b6197106ec 100644
--- a/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c
+++ b/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c
@@ -3709,6 +3709,7 @@ lxpr_read_diskstats(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
for (i = 1; i < nidx; i++) {
kstat_t *ksp = &ksr[i];
kstat_io_t *kip;
+ int major, minor;
if (ksp->ks_type != KSTAT_TYPE_IO ||
strcmp(ksp->ks_class, "disk") != 0)
@@ -3754,13 +3755,32 @@ lxpr_read_diskstats(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf)
* This is also a lie of sorts, but it should be more
* immediately clear to the user that reads and writes are
* each being double-counted as the other.
+ *
+ * Since certain consumers interpret the major/minor numbers to
+ * infer device names, some translation is required to avoid
+ * output which results in totally unexpected results.
*/
+ minor = ksp->ks_instance;
+ if (strncmp(ksp->ks_name, "sd", 2) == 0) {
+ /* map sd[0-9]+ to sd[a-z]+ */
+ major = 8;
+ minor = minor * 16;
+ } else if (strncmp(ksp->ks_name, "ram", 3) == 0) {
+ /* map ramdisk[0-9]+ to ram[0-9]+ */
+ major = 1;
+ } else if (strcmp(ksp->ks_module, "zfs") == 0) {
+ /* map zfs pools to md[0-9]+ (software RAID) */
+ major = 9;
+ } else {
+ /* pretend everything else is ide */
+ major = 2;
+ minor = minor * 64;
+ }
lxpr_uiobuf_printf(uiobuf, "%4d %7d %s "
"%llu %llu %llu %llu "
"%llu %llu %llu %llu "
"%llu %llu %llu\n",
- mod_name_to_major(ksp->ks_module),
- ksp->ks_instance, ksp->ks_name,
+ major, minor, ksp->ks_name,
(uint64_t)kip->reads, 0LL,
kip->nread / (uint64_t)LXPR_SECTOR_SIZE,
(kip->rtime + kip->wtime) / (uint64_t)(NANOSEC / MILLISEC),
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 b62609dfb1..e46dc0496d 100644
--- a/usr/src/uts/common/brand/lx/sysfs/lx_sysfs.h
+++ b/usr/src/uts/common/brand/lx/sysfs/lx_sysfs.h
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2015 Joyent, Inc.
+ * Copyright 2016 Joyent, Inc.
*/
#ifndef _LXSYSFS_H
@@ -98,6 +98,8 @@ typedef enum lxsys_nodetype {
LXSYS_STATIC, /* Statically defined entries */
LXSYS_CLASS_NET, /* /sys/class/net/<iface> */
LXSYS_DEVICES_NET, /* /sys/devices/virtual/net/<iface> */
+ LXSYS_BLOCK, /* /sys/block/<dev> */
+ LXSYS_DEVICES_BDI, /* /sys/devices/virtual/bdi/<dev> */
LXSYS_MAXTYPE, /* type limit */
} lxsys_nodetype_t;
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 1202e943b7..70cf0635c7 100644
--- a/usr/src/uts/common/brand/lx/sysfs/lx_sysvnops.c
+++ b/usr/src/uts/common/brand/lx/sysfs/lx_sysvnops.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright 2015 Joyent, Inc.
+ * Copyright 2016 Joyent, Inc.
*/
/*
@@ -42,6 +42,7 @@
#include <sys/netstack.h>
#include <sys/ethernet.h>
#include <inet/ip_arp.h>
+#include <sys/kstat.h>
#include "lx_sysfs.h"
@@ -71,14 +72,19 @@ static void lxsys_inactive(vnode_t *, cred_t *, caller_context_t *);
static vnode_t *lxsys_lookup_static(lxsys_node_t *, char *);
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 int lxsys_read_devices_virtual_net(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_readlink_class_net(lxsys_node_t *lnp, char *buf, size_t len);
+static int lxsys_readlink_class_net(lxsys_node_t *, char *, size_t);
+static int lxsys_readlink_block(lxsys_node_t *, char *, size_t);
/*
* The lx /sys vnode operations vector
@@ -111,17 +117,21 @@ const fs_operation_def_t lxsys_vnodeops_template[] = {
* 1 - SYS_STATIC
* 2 - SYS_CLASS_NET
* 3 - SYS_DEVICES_NET
+ * 4 - SYS_BLOCK
+ * 5 - SYS_DEVICES_BDI
*
* Static entries will have assigned INSTANCE identifiers:
- * - 0: /sys
- * - 1: /sys/class
- * - 2: /sys/devices
- * - 3: /sys/fs
- * - 4: /sys/class/net
- * - 5: /sys/devices/virtual
- * - 7: /sys/devices/system
- * - 8: /sys/fs/cgroup
- * - 9: /sys/devices/virtual/net
+ * - 0x00: /sys
+ * - 0x01: /sys/class
+ * - 0x02: /sys/devices
+ * - 0x03: /sys/fs
+ * - 0x04: /sys/class/net
+ * - 0x05: /sys/devices/virtual
+ * - 0x06: /sys/devices/system
+ * - 0x07: /sys/fs/cgroup
+ * - 0x08: /sys/devices/virtual/net
+ * - 0x09: /sys/block
+ * - 0x0a: /sys/devices/virtual/bdi
*
* Dynamic /sys/class/net/<interface> symlinks will use an INSTANCE derived
* from the corresonding ifindex.
@@ -129,21 +139,28 @@ const fs_operation_def_t lxsys_vnodeops_template[] = {
* Dynamic /sys/devices/virtual/net/<interface>/<entries> directories will use
* 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.
*/
-#define LXSYS_INST_CLASSDIR 1
-#define LXSYS_INST_DEVICESDIR 2
-#define LXSYS_INST_FSDIR 3
-#define LXSYS_INST_CLASS_NETDIR 4
-#define LXSYS_INST_DEVICES_VIRTUALDIR 5
-#define LXSYS_INST_DEVICES_SYSTEMDIR 6
-#define LXSYS_INST_FS_CGROUPDIR 7
-#define LXSYS_INST_DEVICES_VIRTUAL_NETDIR 8
+#define LXSYS_INST_CLASSDIR 0x1
+#define LXSYS_INST_DEVICESDIR 0x2
+#define LXSYS_INST_FSDIR 0x3
+#define LXSYS_INST_CLASS_NETDIR 0x4
+#define LXSYS_INST_DEVICES_VIRTUALDIR 0x5
+#define LXSYS_INST_DEVICES_SYSTEMDIR 0x6
+#define LXSYS_INST_FS_CGROUPDIR 0x7
+#define LXSYS_INST_DEVICES_VIRTUAL_NETDIR 0x8
+#define LXSYS_INST_BLOCKDIR 0x9
+#define LXSYS_INST_DEVICES_VIRTUAL_BDIDIR 0xa
/*
* file contents of an lx /sys directory.
*/
static lxsys_dirent_t dirlist_root[] = {
+ { LXSYS_INST_BLOCKDIR, "block" },
{ LXSYS_INST_CLASSDIR, "class" },
{ LXSYS_INST_DEVICESDIR, "devices" },
{ LXSYS_INST_FSDIR, "fs" }
@@ -160,6 +177,7 @@ static lxsys_dirent_t dirlist_devices[] = {
{ LXSYS_INST_DEVICES_VIRTUALDIR, "virtual" }
};
static lxsys_dirent_t dirlist_devices_virtual[] = {
+ { LXSYS_INST_DEVICES_VIRTUAL_BDIDIR, "bdi" },
{ LXSYS_INST_DEVICES_VIRTUAL_NETDIR, "net" }
};
@@ -204,6 +222,8 @@ static vnode_t *(*lxsys_lookup_function[LXSYS_MAXTYPE])() = {
lxsys_lookup_static, /* LXSYS_STATIC */
lxsys_lookup_class_netdir, /* LXSYS_CLASS_NET */
lxsys_lookup_devices_virtual_netdir, /* LXSYS_DEVICES_NET */
+ lxsys_lookup_blockdir, /* LXSYS_BLOCK */
+ lxsys_lookup_devices_virtual_bdidir, /* LXSYS_DEVICES_BDI */
};
/*
@@ -214,6 +234,8 @@ static int (*lxsys_readdir_function[LXSYS_MAXTYPE])() = {
lxsys_readdir_static, /* LXSYS_STATIC */
lxsys_readdir_class_netdir, /* LXSYS_CLASS_NET */
lxsys_readdir_devices_virtual_netdir, /* LXSYS_DEVICES_NET */
+ lxsys_readdir_blockdir, /* LXSYS_BLOCK */
+ lxsys_readdir_devices_virtual_bdidir, /* LXSYS_DEVICES_BDI */
};
/*
@@ -224,6 +246,8 @@ static int (*lxsys_read_function[LXSYS_MAXTYPE])() = {
NULL, /* LXSYS_STATIC */
NULL, /* LXSYS_CLASS_NET */
lxsys_read_devices_virtual_net, /* LXSYS_DEVICES_NET */
+ NULL, /* LXSYS_BLOCK */
+ NULL, /* LXSYS_DEVICES_BDI */
};
/*
@@ -234,9 +258,106 @@ static int (*lxsys_readlink_function[LXSYS_MAXTYPE])() = {
NULL, /* LXSYS_STATIC */
lxsys_readlink_class_net, /* LXSYS_CLASS_NET */
NULL, /* LXSYS_DEVICES_NET */
+ lxsys_readlink_block, /* LXSYS_BLOCK */
+ NULL, /* LXSYS_DEVICES_BDI */
};
+/*
+ * Utility functions
+ */
+static void *
+lxsys_kstat_read(kstat_t *kn, boolean_t byname, size_t *size, int *num)
+{
+ kstat_t *kp;
+ int i, nrec = 0;
+ size_t bufsize;
+ void *buf = NULL;
+
+ if (byname == B_TRUE) {
+ kp = kstat_hold_byname(kn->ks_module, kn->ks_instance,
+ kn->ks_name, getzoneid());
+ } else {
+ kp = kstat_hold_bykid(kn->ks_kid, getzoneid());
+ }
+ if (kp == NULL) {
+ return (NULL);
+ }
+ if (kp->ks_flags & KSTAT_FLAG_INVALID) {
+ kstat_rele(kp);
+ return (NULL);
+ }
+
+ bufsize = kp->ks_data_size + 1;
+ kstat_rele(kp);
+
+ /*
+ * The kstat in question is released so that kmem_alloc(KM_SLEEP) is
+ * performed without it held. After the alloc, the kstat is reacquired
+ * and its size is checked again. If the buffer is no longer large
+ * enough, the alloc and check are repeated up to three times.
+ */
+ for (i = 0; i < 2; i++) {
+ buf = kmem_alloc(bufsize, KM_SLEEP);
+
+ /* Check if bufsize still appropriate */
+ if (byname == B_TRUE) {
+ kp = kstat_hold_byname(kn->ks_module, kn->ks_instance,
+ kn->ks_name, getzoneid());
+ } else {
+ kp = kstat_hold_bykid(kn->ks_kid, getzoneid());
+ }
+ if (kp == NULL || kp->ks_flags & KSTAT_FLAG_INVALID) {
+ if (kp != NULL) {
+ kstat_rele(kp);
+ }
+ kmem_free(buf, bufsize);
+ return (NULL);
+ }
+ KSTAT_ENTER(kp);
+ (void) KSTAT_UPDATE(kp, KSTAT_READ);
+ if (bufsize < kp->ks_data_size) {
+ kmem_free(buf, bufsize);
+ buf = NULL;
+ bufsize = kp->ks_data_size + 1;
+ KSTAT_EXIT(kp);
+ kstat_rele(kp);
+ continue;
+ } else {
+ if (KSTAT_SNAPSHOT(kp, buf, KSTAT_READ) != 0) {
+ kmem_free(buf, bufsize);
+ buf = NULL;
+ }
+ nrec = kp->ks_ndata;
+ KSTAT_EXIT(kp);
+ kstat_rele(kp);
+ break;
+ }
+ }
+
+ if (buf != NULL) {
+ *size = bufsize;
+ *num = nrec;
+ }
+ return (buf);
+}
+
+static int
+lxsys_disk_instance(kstat_t *ksp)
+{
+ int result;
+
+ /*
+ * 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.
+ */
+ result = (mod_name_to_major(ksp->ks_module) & 0xff) << 8;
+ result |= (ksp->ks_instance & 0xff);
+ return (result);
+}
+
+
/*
* lxsys_open(): Vnode operation for VOP_OPEN()
@@ -409,6 +530,37 @@ lxsys_lookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pathp,
return ((*vpp == NULL) ? ENOENT : 0);
}
+static lxsys_node_t *
+lxsys_lookup_disk(lxsys_node_t *ldp, char *comp, lxsys_nodetype_t type)
+{
+ kstat_t ks0, *ksr;
+ int nidx, i;
+ size_t sidx;
+ lxsys_node_t *lnp = NULL;
+
+ ks0.ks_kid = 0;
+ ksr = (kstat_t *)lxsys_kstat_read(&ks0, B_FALSE, &sidx, &nidx);
+ if (ksr == NULL) {
+ return (NULL);
+ }
+ 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) {
+ continue;
+ }
+ if (strncmp(ksp->ks_name, comp, KSTAT_STRLEN) == 0 &&
+ (inst = lxsys_disk_instance(ksp)) != 0) {
+ lnp = lxsys_getnode(ldp->lxsys_vnode, type, inst, 0);
+ break;
+ }
+ }
+ kmem_free(ksr, sidx);
+ return (lnp);
+}
+
static vnode_t *
lxsys_lookup_static(lxsys_node_t *ldp, char *comp)
{
@@ -433,12 +585,18 @@ lxsys_lookup_static(lxsys_node_t *ldp, char *comp)
lxsys_node_t *lnp;
switch (dirent[i].d_idnum) {
+ case LXSYS_INST_BLOCKDIR:
+ node_type = LXSYS_BLOCK;
+ break;
case LXSYS_INST_CLASS_NETDIR:
node_type = LXSYS_CLASS_NET;
break;
case LXSYS_INST_DEVICES_VIRTUAL_NETDIR:
node_type = LXSYS_DEVICES_NET;
break;
+ case LXSYS_INST_DEVICES_VIRTUAL_BDIDIR:
+ node_type = LXSYS_DEVICES_BDI;
+ break;
default:
/* Another static node */
node_instance = dirent[i].d_idnum;
@@ -554,6 +712,41 @@ lxsys_lookup_devices_virtual_netdir(lxsys_node_t *ldp, char *comp)
return (NULL);
}
+static vnode_t *
+lxsys_lookup_blockdir(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_BLOCK);
+
+ if (lnp != NULL) {
+ lnp->lxsys_vnode->v_type = VLNK;
+ return (lnp->lxsys_vnode);
+ }
+ }
+
+ return (NULL);
+}
+
+static vnode_t *
+lxsys_lookup_devices_virtual_bdidir(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_BDI);
+
+ if (lnp != NULL) {
+ return (lnp->lxsys_vnode);
+ }
+ }
+
+ return (NULL);
+}
+
static int
lxsys_read_devices_virtual_net(lxsys_node_t *lnp, lxsys_uiobuf_t *luio)
@@ -927,6 +1120,74 @@ lxsys_readdir_ifaces(lxsys_node_t *ldp, struct uio *uiop, int *eofp,
return (error);
}
+static int
+lxsys_readdir_disks(lxsys_node_t *ldp, struct uio *uiop, int *eofp,
+ lxsys_nodetype_t type)
+{
+ longlong_t bp[DIRENT64_RECLEN(LXSNSIZ) / sizeof (longlong_t)];
+ dirent64_t *dirent = (dirent64_t *)bp;
+ ssize_t oresid, uresid;
+ kstat_t ks0, *ksr;
+ int nidx, i, skip, error;
+ size_t sidx;
+
+ /* Emit "." and ".." entries */
+ oresid = uiop->uio_resid;
+ error = lxsys_readdir_common(ldp, uiop, eofp, NULL, 0);
+ if (error != 0 || *eofp == 0) {
+ return (error);
+ }
+
+ 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) {
+ continue;
+ }
+ if ((instance = lxsys_disk_instance(ksp)) == 0) {
+ continue;
+ }
+ if (skip > 0) {
+ skip--;
+ continue;
+ }
+
+ (void) strncpy(dirent->d_name, ksp->ks_name, KSTAT_STRLEN);
+ 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;
+ }
+ }
+
+ /* Indicate EOF if we reached the end of the kstats. */
+ if (i >= nidx) {
+ *eofp = 1;
+ }
+ kmem_free(ksr, sidx);
+
+ return (error);
+}
+
static int
lxsys_readdir_static(lxsys_node_t *lnp, uio_t *uiop, int *eofp)
@@ -987,6 +1248,42 @@ lxsys_readdir_devices_virtual_netdir(lxsys_node_t *lnp, uio_t *uiop, int *eofp)
return (error);
}
+static int
+lxsys_readdir_blockdir(lxsys_node_t *lnp, uio_t *uiop, int *eofp)
+{
+ if (lnp->lxsys_type != LXSYS_BLOCK ||
+ lnp->lxsys_instance != 0) {
+ /*
+ * Since /sys/block contains only symlinks, readdir operations
+ * should not be performed anywhere except the top level
+ * (instance == 0).
+ */
+ return (ENOTDIR);
+ }
+
+ return (lxsys_readdir_disks(lnp, uiop, eofp, LXSYS_BLOCK));
+}
+
+static int
+lxsys_readdir_devices_virtual_bdidir(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_NET);
+ } else if (lnp->lxsys_endpoint == 0) {
+ /* disk-level sub-item listing (empty for now) */
+ error = lxsys_readdir_subdir(lnp, uiop, eofp, NULL, 0);
+ } else {
+ /* there shouldn't be subdirs below this */
+ error = ENOTDIR;
+ }
+
+ return (error);
+}
+
/*
* lxsys_readlink(): Vnode operation for VOP_READLINK()
*/
@@ -1055,6 +1352,41 @@ lxsys_readlink_class_net(lxsys_node_t *lnp, char *buf, size_t len)
return (error);
}
+static int
+lxsys_readlink_block(lxsys_node_t *lnp, char *buf, size_t len)
+{
+ kstat_t *ksr;
+ kstat_t ks0;
+ int nidx, i, inst, error = EINVAL;
+ size_t sidx;
+
+ if ((inst = lnp->lxsys_instance) == 0) {
+ return (error);
+ }
+
+ ks0.ks_kid = 0;
+ ksr = (kstat_t *)lxsys_kstat_read(&ks0, B_FALSE, &sidx, &nidx);
+ if (ksr == NULL) {
+ return (error);
+ }
+ for (i = 1; i < nidx; i++) {
+ kstat_t *ksp = &ksr[i];
+
+ if (ksp->ks_type != KSTAT_TYPE_IO ||
+ strcmp(ksp->ks_class, "disk") != 0) {
+ continue;
+ }
+ if (lxsys_disk_instance(ksp) == inst) {
+ (void) snprintf(buf, len,
+ "/sys/devices/virtual/bdi/%s", ksp->ks_name);
+ error = 0;
+ break;
+ }
+ }
+ kmem_free(ksr, sidx);
+ return (error);
+}
+
/*
* lxsys_inactive(): Vnode operation for VOP_INACTIVE()
* Vnode is no longer referenced, deallocate the file
diff --git a/usr/src/uts/common/fs/ufs/ufs_subr.c b/usr/src/uts/common/fs/ufs/ufs_subr.c
index 0ef1f8280d..4746d9e15e 100644
--- a/usr/src/uts/common/fs/ufs/ufs_subr.c
+++ b/usr/src/uts/common/fs/ufs/ufs_subr.c
@@ -602,7 +602,7 @@ ufs_sync_indir(struct inode *ip)
}
/* Write out all the first level indirect blocks */
- for (i = 0; i <= NIADDR; i++) {
+ for (i = 0; i < NIADDR; i++) {
if ((blkno = ip->i_ib[i]) == 0)
continue;
blkflush(ip->i_dev, (daddr_t)fsbtodb(fs, blkno));
diff --git a/usr/src/uts/common/inet/ip/conn_opt.c b/usr/src/uts/common/inet/ip/conn_opt.c
index 218f9f7154..b4bff4d7b4 100644
--- a/usr/src/uts/common/inet/ip/conn_opt.c
+++ b/usr/src/uts/common/inet/ip/conn_opt.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2015 Joyent, Inc.
+ * Copyright 2016 Joyent, Inc.
*/
/* Copyright (c) 1990 Mentat Inc. */
@@ -1190,8 +1190,24 @@ conn_opt_set_ip(conn_opt_arg_t *coa, t_scalar_t name, uint_t inlen,
ip_stack_t *ipst = connp->conn_netstack->netstack_ip;
int error;
- if (connp->conn_family != AF_INET)
+ if (connp->conn_family == AF_INET6 &&
+ connp->conn_ipversion == IPV4_VERSION) {
+ /*
+ * Allow certain IPv4 options to be set on an AF_INET6 socket
+ * if the connection is still IPv4.
+ */
+ switch (name) {
+ case IP_TOS:
+ case T_IP_TOS:
+ case IP_TTL:
+ case IP_DONTFRAG:
+ break;
+ default:
+ return (EINVAL);
+ }
+ } else if (connp->conn_family != AF_INET) {
return (EINVAL);
+ }
switch (name) {
case IP_TTL:
diff --git a/usr/src/uts/common/inet/tcp/tcp_opt_data.c b/usr/src/uts/common/inet/tcp/tcp_opt_data.c
index bdc9482b45..861be92c38 100644
--- a/usr/src/uts/common/inet/tcp/tcp_opt_data.c
+++ b/usr/src/uts/common/inet/tcp/tcp_opt_data.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright 2015 Joyent, Inc.
+ * Copyright 2016 Joyent, Inc.
*/
#include <sys/types.h>
@@ -996,10 +996,6 @@ tcp_opt_set(conn_t *connp, uint_t optset_context, int level, int name,
}
break;
case IPPROTO_IP:
- if (connp->conn_family != AF_INET) {
- *outlenp = 0;
- return (EINVAL);
- }
switch (name) {
case IP_SEC_OPT:
/*
diff --git a/usr/src/uts/sun4u/cpu/common_asm.s b/usr/src/uts/sun4u/cpu/common_asm.s
index a3e2343c89..aee74db442 100644
--- a/usr/src/uts/sun4u/cpu/common_asm.s
+++ b/usr/src/uts/sun4u/cpu/common_asm.s
@@ -808,6 +808,29 @@ kstat_q_panic_msg:
QRETURN; \
stx %g1, [%o0 + QTYPE/**/LASTUPDATE]; /* lastupdate = now */
+#if !defined(DEBUG)
+/*
+ * same as KSTAT_Q_UPDATE but without:
+ * QBR %o1, QZERO;
+ * to be used only with non-debug build. mimics ASSERT() behaviour.
+ */
+#define KSTAT_Q_UPDATE_ND(QOP, QRETURN, QTYPE) \
+ ld [%o0 + QTYPE/**/CNT], %o1; /* %o1 = old qlen */ \
+ QOP %o1, 1, %o2; /* %o2 = new qlen */ \
+ st %o2, [%o0 + QTYPE/**/CNT]; /* delay: save qlen */ \
+ ldx [%o0 + QTYPE/**/LASTUPDATE], %o3; \
+ ldx [%o0 + QTYPE/**/TIME], %o4; /* %o4 = old time */ \
+ ldx [%o0 + QTYPE/**/LENTIME], %o5; /* %o5 = old lentime */ \
+ sub %g1, %o3, %o2; /* %o2 = time delta */ \
+ mulx %o1, %o2, %o3; /* %o3 = cur lentime */ \
+ add %o4, %o2, %o4; /* %o4 = new time */ \
+ add %o5, %o3, %o5; /* %o5 = new lentime */ \
+ stx %o4, [%o0 + QTYPE/**/TIME]; /* save time */ \
+ stx %o5, [%o0 + QTYPE/**/LENTIME]; /* save lentime */ \
+QRETURN; \
+ stx %g1, [%o0 + QTYPE/**/LASTUPDATE]; /* lastupdate = now */
+#endif
+
.align 16
ENTRY(kstat_waitq_enter)
GET_NATIVE_TIME(%g1, %g2, %g3)
@@ -817,7 +840,11 @@ QRETURN; \
.align 16
ENTRY(kstat_waitq_exit)
GET_NATIVE_TIME(%g1, %g2, %g3)
+#if defined(DEBUG)
KSTAT_Q_UPDATE(sub, BRZPN, kstat_q_panic, retl, KSTAT_IO_W)
+#else
+ KSTAT_Q_UPDATE_ND(sub, retl, KSTAT_IO_W)
+#endif
SET_SIZE(kstat_waitq_exit)
.align 16
@@ -829,20 +856,32 @@ QRETURN; \
.align 16
ENTRY(kstat_runq_exit)
GET_NATIVE_TIME(%g1, %g2, %g3)
+#if defined(DEBUG)
KSTAT_Q_UPDATE(sub, BRZPN, kstat_q_panic, retl, KSTAT_IO_R)
+#else
+ KSTAT_Q_UPDATE_ND(sub, retl, KSTAT_IO_R)
+#endif
SET_SIZE(kstat_runq_exit)
.align 16
ENTRY(kstat_waitq_to_runq)
GET_NATIVE_TIME(%g1, %g2, %g3)
+#if defined(DEBUG)
KSTAT_Q_UPDATE(sub, BRZPN, kstat_q_panic, 1:, KSTAT_IO_W)
+#else
+ KSTAT_Q_UPDATE_ND(sub, 1:, KSTAT_IO_W)
+#endif
KSTAT_Q_UPDATE(add, BRZPT, 1f, 1:retl, KSTAT_IO_R)
SET_SIZE(kstat_waitq_to_runq)
.align 16
ENTRY(kstat_runq_back_to_waitq)
GET_NATIVE_TIME(%g1, %g2, %g3)
+#if defined(DEBUG)
KSTAT_Q_UPDATE(sub, BRZPN, kstat_q_panic, 1:, KSTAT_IO_R)
+#else
+ KSTAT_Q_UPDATE_ND(sub, 1:, KSTAT_IO_R)
+#endif
KSTAT_Q_UPDATE(add, BRZPT, 1f, 1:retl, KSTAT_IO_W)
SET_SIZE(kstat_runq_back_to_waitq)
diff --git a/usr/src/uts/sun4v/cpu/common_asm.s b/usr/src/uts/sun4v/cpu/common_asm.s
index ff08ef97f6..fda53b4d2a 100644
--- a/usr/src/uts/sun4v/cpu/common_asm.s
+++ b/usr/src/uts/sun4v/cpu/common_asm.s
@@ -654,6 +654,29 @@ kstat_q_panic_msg:
QRETURN; \
stx %g1, [%o0 + QTYPE/**/LASTUPDATE]; /* lastupdate = now */
+#if !defined(DEBUG)
+/*
+ * same as KSTAT_Q_UPDATE but without:
+ * QBR %o1, QZERO;
+ * to be used only with non-debug build. mimics ASSERT() behaviour.
+ */
+#define KSTAT_Q_UPDATE_ND(QOP, QRETURN, QTYPE) \
+ ld [%o0 + QTYPE/**/CNT], %o1; /* %o1 = old qlen */ \
+ QOP %o1, 1, %o2; /* %o2 = new qlen */ \
+ st %o2, [%o0 + QTYPE/**/CNT]; /* delay: save qlen */ \
+ ldx [%o0 + QTYPE/**/LASTUPDATE], %o3; \
+ ldx [%o0 + QTYPE/**/TIME], %o4; /* %o4 = old time */ \
+ ldx [%o0 + QTYPE/**/LENTIME], %o5; /* %o5 = old lentime */ \
+ sub %g1, %o3, %o2; /* %o2 = time delta */ \
+ mulx %o1, %o2, %o3; /* %o3 = cur lentime */ \
+ add %o4, %o2, %o4; /* %o4 = new time */ \
+ add %o5, %o3, %o5; /* %o5 = new lentime */ \
+ stx %o4, [%o0 + QTYPE/**/TIME]; /* save time */ \
+ stx %o5, [%o0 + QTYPE/**/LENTIME]; /* save lentime */ \
+QRETURN; \
+ stx %g1, [%o0 + QTYPE/**/LASTUPDATE]; /* lastupdate = now */
+#endif
+
.align 16
ENTRY(kstat_waitq_enter)
GET_NATIVE_TIME(%g1,%g2,%g3,__LINE__)
@@ -663,7 +686,11 @@ QRETURN; \
.align 16
ENTRY(kstat_waitq_exit)
GET_NATIVE_TIME(%g1,%g2,%g3,__LINE__)
+#if defined(DEBUG)
KSTAT_Q_UPDATE(sub, BRZPN, kstat_q_panic, retl, KSTAT_IO_W)
+#else
+ KSTAT_Q_UPDATE_ND(sub, retl, KSTAT_IO_W)
+#endif
SET_SIZE(kstat_waitq_exit)
.align 16
@@ -675,20 +702,32 @@ QRETURN; \
.align 16
ENTRY(kstat_runq_exit)
GET_NATIVE_TIME(%g1,%g2,%g3,__LINE__)
+#if defined(DEBUG)
KSTAT_Q_UPDATE(sub, BRZPN, kstat_q_panic, retl, KSTAT_IO_R)
+#else
+ KSTAT_Q_UPDATE_ND(sub, retl, KSTAT_IO_R)
+#endif
SET_SIZE(kstat_runq_exit)
.align 16
ENTRY(kstat_waitq_to_runq)
GET_NATIVE_TIME(%g1,%g2,%g3,__LINE__)
+#if defined(DEBUG)
KSTAT_Q_UPDATE(sub, BRZPN, kstat_q_panic, 1:, KSTAT_IO_W)
+#else
+ KSTAT_Q_UPDATE_ND(sub, 1:, KSTAT_IO_W)
+#endif
KSTAT_Q_UPDATE(add, BRZPT, 1f, 1:retl, KSTAT_IO_R)
SET_SIZE(kstat_waitq_to_runq)
.align 16
ENTRY(kstat_runq_back_to_waitq)
GET_NATIVE_TIME(%g1,%g2,%g3,__LINE__)
+#if defined(DEBUG)
KSTAT_Q_UPDATE(sub, BRZPN, kstat_q_panic, 1:, KSTAT_IO_R)
+#else
+ KSTAT_Q_UPDATE_ND(sub, 1:, KSTAT_IO_R)
+#endif
KSTAT_Q_UPDATE(add, BRZPT, 1f, 1:retl, KSTAT_IO_W)
SET_SIZE(kstat_runq_back_to_waitq)