Index: stable/11/sys/geom/geom_disk.h =================================================================== --- stable/11/sys/geom/geom_disk.h (revision 325002) +++ stable/11/sys/geom/geom_disk.h (revision 325003) @@ -1,145 +1,145 @@ /*- * Copyright (c) 2003 Poul-Henning Kamp * All rights reserved. * * This software was developed for the FreeBSD Project by Poul-Henning Kamp * and NAI Labs, the Security Research Division of Network Associates, Inc. * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the * DARPA CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The names of the authors may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _GEOM_GEOM_DISK_H_ #define _GEOM_GEOM_DISK_H_ +#define DISK_RR_UNKNOWN 0 +#define DISK_RR_NON_ROTATING 1 +#define DISK_RR_MIN 0x0401 +#define DISK_RR_MAX 0xfffe + #ifdef _KERNEL #include #include #include #include #define G_DISK_CLASS_NAME "DISK" struct disk; typedef int disk_open_t(struct disk *); typedef int disk_close_t(struct disk *); typedef void disk_strategy_t(struct bio *bp); typedef int disk_getattr_t(struct bio *bp); typedef void disk_gone_t(struct disk *); typedef int disk_ioctl_t(struct disk *, u_long cmd, void *data, int fflag, struct thread *td); /* NB: disk_ioctl_t SHALL be cast'able to d_ioctl_t */ struct g_geom; struct devstat; typedef enum { DISK_INIT_NONE, DISK_INIT_START, DISK_INIT_DONE } disk_init_level; struct disk { /* Fields which are private to geom_disk */ struct g_geom *d_geom; struct devstat *d_devstat; int d_goneflag; int d_destroyed; disk_init_level d_init_level; /* Shared fields */ u_int d_flags; const char *d_name; u_int d_unit; struct bio_queue_head *d_queue; struct mtx *d_lock; /* Disk methods */ disk_open_t *d_open; disk_close_t *d_close; disk_strategy_t *d_strategy; disk_ioctl_t *d_ioctl; dumper_t *d_dump; disk_getattr_t *d_getattr; disk_gone_t *d_gone; /* Info fields from driver to geom_disk.c. Valid when open */ u_int d_sectorsize; off_t d_mediasize; u_int d_fwsectors; u_int d_fwheads; u_int d_maxsize; off_t d_delmaxsize; u_int d_stripeoffset; u_int d_stripesize; char d_ident[DISK_IDENT_SIZE]; char d_descr[DISK_IDENT_SIZE]; uint16_t d_hba_vendor; uint16_t d_hba_device; uint16_t d_hba_subvendor; uint16_t d_hba_subdevice; uint16_t d_rotation_rate; /* Fields private to the driver */ void *d_drv1; }; #define DISKFLAG_RESERVED 0x1 /* Was NEEDSGIANT */ #define DISKFLAG_OPEN 0x2 #define DISKFLAG_CANDELETE 0x4 #define DISKFLAG_CANFLUSHCACHE 0x8 #define DISKFLAG_UNMAPPED_BIO 0x10 #define DISKFLAG_DIRECT_COMPLETION 0x20 #define DISKFLAG_CANZONE 0x80 - -#define DISK_RR_UNKNOWN 0 -#define DISK_RR_NON_ROTATING 1 -#define DISK_RR_MIN 0x0401 -#define DISK_RR_MAX 0xfffe struct disk *disk_alloc(void); void disk_create(struct disk *disk, int version); void disk_destroy(struct disk *disk); void disk_gone(struct disk *disk); void disk_attr_changed(struct disk *dp, const char *attr, int flag); void disk_media_changed(struct disk *dp, int flag); void disk_media_gone(struct disk *dp, int flag); int disk_resize(struct disk *dp, int flag); #define DISK_VERSION_00 0x58561059 #define DISK_VERSION_01 0x5856105a #define DISK_VERSION_02 0x5856105b #define DISK_VERSION_03 0x5856105c #define DISK_VERSION_04 0x5856105d #define DISK_VERSION_05 0x5856105e #define DISK_VERSION DISK_VERSION_05 #endif /* _KERNEL */ #endif /* _GEOM_GEOM_DISK_H_ */ Index: stable/11/sys/sys/disk.h =================================================================== --- stable/11/sys/sys/disk.h (revision 325002) +++ stable/11/sys/sys/disk.h (revision 325003) @@ -1,142 +1,143 @@ /*- * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * * $FreeBSD$ * */ #ifndef _SYS_DISK_H_ #define _SYS_DISK_H_ #include #include #include #ifdef _KERNEL #ifndef _SYS_CONF_H_ #include /* XXX: temporary to avoid breakage */ #endif void disk_err(struct bio *bp, const char *what, int blkdone, int nl); #endif #define DIOCGSECTORSIZE _IOR('d', 128, u_int) /* * Get the sector size of the device in bytes. The sector size is the * smallest unit of data which can be transferred from this device. * Usually this is a power of 2 but it might not be (i.e. CDROM audio). */ #define DIOCGMEDIASIZE _IOR('d', 129, off_t) /* Get media size in bytes */ /* * Get the size of the entire device in bytes. This should be a * multiple of the sector size. */ #define DIOCGFWSECTORS _IOR('d', 130, u_int) /* Get firmware's sectorcount */ /* * Get the firmware's notion of number of sectors per track. This * value is mostly used for compatibility with various ill designed * disk label formats. Don't use it unless you have to. */ #define DIOCGFWHEADS _IOR('d', 131, u_int) /* Get firmware's headcount */ /* * Get the firmwares notion of number of heads per cylinder. This * value is mostly used for compatibility with various ill designed * disk label formats. Don't use it unless you have to. */ #define DIOCSKERNELDUMP _IOW('d', 133, u_int) /* Set/Clear kernel dumps */ /* * Enable/Disable (the argument is boolean) the device for kernel * core dumps. */ #define DIOCGFRONTSTUFF _IOR('d', 134, off_t) /* * Many disk formats have some amount of space reserved at the * start of the disk to hold bootblocks, various disklabels and * similar stuff. This ioctl returns the number of such bytes * which may apply to the device. */ #define DIOCGFLUSH _IO('d', 135) /* Flush write cache */ /* * Flush write cache of the device. */ #define DIOCGDELETE _IOW('d', 136, off_t[2]) /* Delete data */ /* * Mark data on the device as unused. */ #define DISK_IDENT_SIZE 256 #define DIOCGIDENT _IOR('d', 137, char[DISK_IDENT_SIZE]) /*- * Get the ident of the given provider. Ident is (most of the time) * a uniqe and fixed provider's identifier. Ident's properties are as * follow: * - ident value is preserved between reboots, * - provider can be detached/attached and ident is preserved, * - provider's name can change - ident can't, * - ident value should not be based on on-disk metadata; in other * words copying whole data from one disk to another should not * yield the same ident for the other disk, * - there could be more than one provider with the same ident, but * only if they point at exactly the same physical storage, this is * the case for multipathing for example, * - GEOM classes that consumes single providers and provide single * providers, like geli, gbde, should just attach class name to the * ident of the underlying provider, * - ident is an ASCII string (is printable), * - ident is optional and applications can't relay on its presence. */ #define DIOCGPROVIDERNAME _IOR('d', 138, char[MAXPATHLEN]) /* * Store the provider name, given a device path, in a buffer. The buffer * must be at least MAXPATHLEN bytes long. */ #define DIOCGSTRIPESIZE _IOR('d', 139, off_t) /* Get stripe size in bytes */ /* * Get the size of the device's optimal access block in bytes. * This should be a multiple of the sector size. */ #define DIOCGSTRIPEOFFSET _IOR('d', 140, off_t) /* Get stripe offset in bytes */ /* * Get the offset of the first device's optimal access block in bytes. * This should be a multiple of the sector size. */ #define DIOCGPHYSPATH _IOR('d', 141, char[MAXPATHLEN]) /* * Get a string defining the physical path for a given provider. * This has similar rules to ident, but is intended to uniquely * identify the physical location of the device, not the current * occupant of that location. */ struct diocgattr_arg { char name[64]; int len; union { char str[DISK_IDENT_SIZE]; off_t off; int i; + uint16_t u16; } value; }; #define DIOCGATTR _IOWR('d', 142, struct diocgattr_arg) #define DIOCZONECMD _IOWR('d', 143, struct disk_zone_args) #endif /* _SYS_DISK_H_ */ Index: stable/11/sys/sys/param.h =================================================================== --- stable/11/sys/sys/param.h (revision 325002) +++ stable/11/sys/sys/param.h (revision 325003) @@ -1,365 +1,365 @@ /*- * Copyright (c) 1982, 1986, 1989, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)param.h 8.3 (Berkeley) 4/4/95 * $FreeBSD$ */ #ifndef _SYS_PARAM_H_ #define _SYS_PARAM_H_ #include #define BSD 199506 /* System version (year & month). */ #define BSD4_3 1 #define BSD4_4 1 /* * __FreeBSD_version numbers are documented in the Porter's Handbook. * If you bump the version for any reason, you should update the documentation * there. * Currently this lives here in the doc/ repository: * * head/en_US.ISO8859-1/books/porters-handbook/versions/chapter.xml * * scheme is: Rxx * 'R' is in the range 0 to 4 if this is a release branch or * X.0-CURRENT before releng/X.0 is created, otherwise 'R' is * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 1101505 /* Master, propagated to newvers */ +#define __FreeBSD_version 1101506 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, * which by definition is always true on FreeBSD. This macro is also defined * on other systems that use the kernel of FreeBSD, such as GNU/kFreeBSD. * * It is tempting to use this macro in userland code when we want to enable * kernel-specific routines, and in fact it's fine to do this in code that * is part of FreeBSD itself. However, be aware that as presence of this * macro is still not widespread (e.g. older FreeBSD versions, 3rd party * compilers, etc), it is STRONGLY DISCOURAGED to check for this macro in * external applications without also checking for __FreeBSD__ as an * alternative. */ #undef __FreeBSD_kernel__ #define __FreeBSD_kernel__ #if defined(_KERNEL) || defined(IN_RTLD) #define P_OSREL_SIGWAIT 700000 #define P_OSREL_SIGSEGV 700004 #define P_OSREL_MAP_ANON 800104 #define P_OSREL_MAP_FSTRICT 1100036 #define P_OSREL_SHUTDOWN_ENOTCONN 1100077 #define P_OSREL_MAP_GUARD 1200035 #define P_OSREL_MAP_GUARD_11 1101501 #define P_OSREL_WRFSBASE 1200041 #define P_OSREL_WRFSBASE_11 1101503 #define P_OSREL_MAJOR(x) ((x) / 100000) #endif #ifndef LOCORE #include #endif /* * Machine-independent constants (some used in following include files). * Redefined constants are from POSIX 1003.1 limits file. * * MAXCOMLEN should be >= sizeof(ac_comm) (see ) */ #include #define MAXCOMLEN 19 /* max command name remembered */ #define MAXINTERP PATH_MAX /* max interpreter file name length */ #define MAXLOGNAME 33 /* max login name length (incl. NUL) */ #define MAXUPRC CHILD_MAX /* max simultaneous processes */ #define NCARGS ARG_MAX /* max bytes for an exec function */ #define NGROUPS (NGROUPS_MAX+1) /* max number groups */ #define NOFILE OPEN_MAX /* max open files per process */ #define NOGROUP 65535 /* marker for empty group set member */ #define MAXHOSTNAMELEN 256 /* max hostname size */ #define SPECNAMELEN 63 /* max length of devicename */ /* More types and definitions used throughout the kernel. */ #ifdef _KERNEL #include #include #ifndef LOCORE #include #include #endif #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif #endif #ifndef _KERNEL /* Signals. */ #include #endif /* Machine type dependent parameters. */ #include #ifndef _KERNEL #include #endif #ifndef DEV_BSHIFT #define DEV_BSHIFT 9 /* log2(DEV_BSIZE) */ #endif #define DEV_BSIZE (1<>PAGE_SHIFT) #endif /* * btodb() is messy and perhaps slow because `bytes' may be an off_t. We * want to shift an unsigned type to avoid sign extension and we don't * want to widen `bytes' unnecessarily. Assume that the result fits in * a daddr_t. */ #ifndef btodb #define btodb(bytes) /* calculates (bytes / DEV_BSIZE) */ \ (sizeof (bytes) > sizeof(long) \ ? (daddr_t)((unsigned long long)(bytes) >> DEV_BSHIFT) \ : (daddr_t)((unsigned long)(bytes) >> DEV_BSHIFT)) #endif #ifndef dbtob #define dbtob(db) /* calculates (db * DEV_BSIZE) */ \ ((off_t)(db) << DEV_BSHIFT) #endif #define PRIMASK 0x0ff #define PCATCH 0x100 /* OR'd with pri for tsleep to check signals */ #define PDROP 0x200 /* OR'd with pri to stop re-entry of interlock mutex */ #define NZERO 0 /* default "nice" */ #define NBBY 8 /* number of bits in a byte */ #define NBPW sizeof(int) /* number of bytes per word (integer) */ #define CMASK 022 /* default file mask: S_IWGRP|S_IWOTH */ #define NODEV (dev_t)(-1) /* non-existent device */ /* * File system parameters and macros. * * MAXBSIZE - Filesystems are made out of blocks of at most MAXBSIZE bytes * per block. MAXBSIZE may be made larger without effecting * any existing filesystems as long as it does not exceed MAXPHYS, * and may be made smaller at the risk of not being able to use * filesystems which require a block size exceeding MAXBSIZE. * * MAXBCACHEBUF - Maximum size of a buffer in the buffer cache. This must * be >= MAXBSIZE and can be set differently for different * architectures by defining it in . * Making this larger allows NFS to do larger reads/writes. * * BKVASIZE - Nominal buffer space per buffer, in bytes. BKVASIZE is the * minimum KVM memory reservation the kernel is willing to make. * Filesystems can of course request smaller chunks. Actual * backing memory uses a chunk size of a page (PAGE_SIZE). * The default value here can be overridden on a per-architecture * basis by defining it in . * * If you make BKVASIZE too small you risk seriously fragmenting * the buffer KVM map which may slow things down a bit. If you * make it too big the kernel will not be able to optimally use * the KVM memory reserved for the buffer cache and will wind * up with too-few buffers. * * The default is 16384, roughly 2x the block size used by a * normal UFS filesystem. */ #define MAXBSIZE 65536 /* must be power of 2 */ #ifndef MAXBCACHEBUF #define MAXBCACHEBUF MAXBSIZE /* must be a power of 2 >= MAXBSIZE */ #endif #ifndef BKVASIZE #define BKVASIZE 16384 /* must be power of 2 */ #endif #define BKVAMASK (BKVASIZE-1) /* * MAXPATHLEN defines the longest permissible path length after expanding * symbolic links. It is used to allocate a temporary buffer from the buffer * pool in which to do the name expansion, hence should be a power of two, * and must be less than or equal to MAXBSIZE. MAXSYMLINKS defines the * maximum number of symbolic links that may be expanded in a path name. * It should be set high enough to allow all legitimate uses, but halt * infinite loops reasonably quickly. */ #define MAXPATHLEN PATH_MAX #define MAXSYMLINKS 32 /* Bit map related macros. */ #define setbit(a,i) (((unsigned char *)(a))[(i)/NBBY] |= 1<<((i)%NBBY)) #define clrbit(a,i) (((unsigned char *)(a))[(i)/NBBY] &= ~(1<<((i)%NBBY))) #define isset(a,i) \ (((const unsigned char *)(a))[(i)/NBBY] & (1<<((i)%NBBY))) #define isclr(a,i) \ ((((const unsigned char *)(a))[(i)/NBBY] & (1<<((i)%NBBY))) == 0) /* Macros for counting and rounding. */ #ifndef howmany #define howmany(x, y) (((x)+((y)-1))/(y)) #endif #define nitems(x) (sizeof((x)) / sizeof((x)[0])) #define rounddown(x, y) (((x)/(y))*(y)) #define rounddown2(x, y) ((x)&(~((y)-1))) /* if y is power of two */ #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) /* to any y */ #define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */ #define powerof2(x) ((((x)-1)&(x))==0) /* Macros for min/max. */ #define MIN(a,b) (((a)<(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b)) #ifdef _KERNEL /* * Basic byte order function prototypes for non-inline functions. */ #ifndef LOCORE #ifndef _BYTEORDER_PROTOTYPED #define _BYTEORDER_PROTOTYPED __BEGIN_DECLS __uint32_t htonl(__uint32_t); __uint16_t htons(__uint16_t); __uint32_t ntohl(__uint32_t); __uint16_t ntohs(__uint16_t); __END_DECLS #endif #endif #ifndef lint #ifndef _BYTEORDER_FUNC_DEFINED #define _BYTEORDER_FUNC_DEFINED #define htonl(x) __htonl(x) #define htons(x) __htons(x) #define ntohl(x) __ntohl(x) #define ntohs(x) __ntohs(x) #endif /* !_BYTEORDER_FUNC_DEFINED */ #endif /* lint */ #endif /* _KERNEL */ /* * Scale factor for scaled integers used to count %cpu time and load avgs. * * The number of CPU `tick's that map to a unique `%age' can be expressed * by the formula (1 / (2 ^ (FSHIFT - 11))). The maximum load average that * can be calculated (assuming 32 bits) can be closely approximated using * the formula (2 ^ (2 * (16 - FSHIFT))) for (FSHIFT < 15). * * For the scheduler to maintain a 1:1 mapping of CPU `tick' to `%age', * FSHIFT must be at least 11; this gives us a maximum load avg of ~1024. */ #define FSHIFT 11 /* bits to right of fixed binary point */ #define FSCALE (1<> (PAGE_SHIFT - DEV_BSHIFT)) #define ctodb(db) /* calculates pages to devblks */ \ ((db) << (PAGE_SHIFT - DEV_BSHIFT)) /* * Old spelling of __containerof(). */ #define member2struct(s, m, x) \ ((struct s *)(void *)((char *)(x) - offsetof(struct s, m))) /* * Access a variable length array that has been declared as a fixed * length array. */ #define __PAST_END(array, offset) (((__typeof__(*(array)) *)(array))[offset]) #endif /* _SYS_PARAM_H_ */ Index: stable/11/usr.sbin/diskinfo/diskinfo.c =================================================================== --- stable/11/usr.sbin/diskinfo/diskinfo.c (revision 325002) +++ stable/11/usr.sbin/diskinfo/diskinfo.c (revision 325003) @@ -1,700 +1,742 @@ /*- * Copyright (c) 2003 Poul-Henning Kamp * Copyright (c) 2015 Spectra Logic Corporation * Copyright (c) 2017 Alexander Motin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The names of the authors may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ +#include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #define NAIO 128 #define MAXTX (8*1024*1024) #define MEGATX (1024*1024) static void usage(void) { fprintf(stderr, "usage: diskinfo [-cipsStvw] disk ...\n"); exit (1); } static int opt_c, opt_i, opt_p, opt_s, opt_S, opt_t, opt_v, opt_w; +static bool candelete(int fd); static void speeddisk(int fd, off_t mediasize, u_int sectorsize); static void commandtime(int fd, off_t mediasize, u_int sectorsize); static void iopsbench(int fd, off_t mediasize, u_int sectorsize); +static void rotationrate(int fd, char *buf, size_t buflen); static void slogbench(int fd, int isreg, off_t mediasize, u_int sectorsize); static int zonecheck(int fd, uint32_t *zone_mode, char *zone_str, size_t zone_str_len); static uint8_t *buf; int main(int argc, char **argv) { struct stat sb; int i, ch, fd, error, exitval = 0; char tstr[BUFSIZ], ident[DISK_IDENT_SIZE], physpath[MAXPATHLEN]; char zone_desc[64]; + char rrate[64]; struct diocgattr_arg arg; off_t mediasize, stripesize, stripeoffset; u_int sectorsize, fwsectors, fwheads, zoned = 0, isreg; uint32_t zone_mode; while ((ch = getopt(argc, argv, "cipsStvw")) != -1) { switch (ch) { case 'c': opt_c = 1; opt_v = 1; break; case 'i': opt_i = 1; opt_v = 1; break; case 'p': opt_p = 1; break; case 's': opt_s = 1; break; case 'S': opt_S = 1; opt_v = 1; break; case 't': opt_t = 1; opt_v = 1; break; case 'v': opt_v = 1; break; case 'w': opt_w = 1; break; default: usage(); } } argc -= optind; argv += optind; if (argc < 1) usage(); if ((opt_p && opt_s) || ((opt_p || opt_s) && (opt_c || opt_i || opt_t || opt_v))) { warnx("-p or -s cannot be used with other options"); usage(); } if (opt_S && !opt_w) { warnx("-S require also -w"); usage(); } if (posix_memalign((void **)&buf, PAGE_SIZE, MAXTX)) errx(1, "Can't allocate memory buffer"); for (i = 0; i < argc; i++) { fd = open(argv[i], (opt_w ? O_RDWR : O_RDONLY) | O_DIRECT); if (fd < 0 && errno == ENOENT && *argv[i] != '/') { snprintf(tstr, sizeof(tstr), "%s%s", _PATH_DEV, argv[i]); fd = open(tstr, O_RDONLY); } if (fd < 0) { warn("%s", argv[i]); exit(1); } error = fstat(fd, &sb); if (error != 0) { warn("cannot stat %s", argv[i]); exitval = 1; goto out; } isreg = S_ISREG(sb.st_mode); if (isreg) { mediasize = sb.st_size; sectorsize = S_BLKSIZE; fwsectors = 0; fwheads = 0; stripesize = sb.st_blksize; stripeoffset = 0; if (opt_p || opt_s) { warnx("-p and -s only operate on physical devices: %s", argv[i]); goto out; } } else { if (opt_p) { if (ioctl(fd, DIOCGPHYSPATH, physpath) == 0) { printf("%s\n", physpath); } else { warnx("Failed to determine physpath for: %s", argv[i]); } goto out; } if (opt_s) { if (ioctl(fd, DIOCGIDENT, ident) == 0) { printf("%s\n", ident); } else { warnx("Failed to determine serial number for: %s", argv[i]); } goto out; } error = ioctl(fd, DIOCGMEDIASIZE, &mediasize); if (error) { warnx("%s: ioctl(DIOCGMEDIASIZE) failed, probably not a disk.", argv[i]); exitval = 1; goto out; } error = ioctl(fd, DIOCGSECTORSIZE, §orsize); if (error) { warnx("%s: ioctl(DIOCGSECTORSIZE) failed, probably not a disk.", argv[i]); exitval = 1; goto out; } error = ioctl(fd, DIOCGFWSECTORS, &fwsectors); if (error) fwsectors = 0; error = ioctl(fd, DIOCGFWHEADS, &fwheads); if (error) fwheads = 0; error = ioctl(fd, DIOCGSTRIPESIZE, &stripesize); if (error) stripesize = 0; error = ioctl(fd, DIOCGSTRIPEOFFSET, &stripeoffset); if (error) stripeoffset = 0; error = zonecheck(fd, &zone_mode, zone_desc, sizeof(zone_desc)); if (error == 0) zoned = 1; } if (!opt_v) { printf("%s", argv[i]); printf("\t%u", sectorsize); printf("\t%jd", (intmax_t)mediasize); printf("\t%jd", (intmax_t)mediasize/sectorsize); printf("\t%jd", (intmax_t)stripesize); printf("\t%jd", (intmax_t)stripeoffset); if (fwsectors != 0 && fwheads != 0) { printf("\t%jd", (intmax_t)mediasize / (fwsectors * fwheads * sectorsize)); printf("\t%u", fwheads); printf("\t%u", fwsectors); } } else { humanize_number(tstr, 5, (int64_t)mediasize, "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); printf("%s\n", argv[i]); printf("\t%-12u\t# sectorsize\n", sectorsize); printf("\t%-12jd\t# mediasize in bytes (%s)\n", (intmax_t)mediasize, tstr); printf("\t%-12jd\t# mediasize in sectors\n", (intmax_t)mediasize/sectorsize); printf("\t%-12jd\t# stripesize\n", stripesize); printf("\t%-12jd\t# stripeoffset\n", stripeoffset); if (fwsectors != 0 && fwheads != 0) { printf("\t%-12jd\t# Cylinders according to firmware.\n", (intmax_t)mediasize / (fwsectors * fwheads * sectorsize)); printf("\t%-12u\t# Heads according to firmware.\n", fwheads); printf("\t%-12u\t# Sectors according to firmware.\n", fwsectors); } strlcpy(arg.name, "GEOM::descr", sizeof(arg.name)); arg.len = sizeof(arg.value.str); if (ioctl(fd, DIOCGATTR, &arg) == 0) printf("\t%-12s\t# Disk descr.\n", arg.value.str); if (ioctl(fd, DIOCGIDENT, ident) == 0) printf("\t%-12s\t# Disk ident.\n", ident); if (ioctl(fd, DIOCGPHYSPATH, physpath) == 0) printf("\t%-12s\t# Physical path\n", physpath); + printf("\t%-12s\t# TRIM/UNMAP support\n", + candelete(fd) ? "Yes" : "No"); + rotationrate(fd, rrate, sizeof(rrate)); + printf("\t%-12s\t# Rotation rate in RPM\n", rrate); if (zoned != 0) printf("\t%-12s\t# Zone Mode\n", zone_desc); } printf("\n"); if (opt_c) commandtime(fd, mediasize, sectorsize); if (opt_t) speeddisk(fd, mediasize, sectorsize); if (opt_i) iopsbench(fd, mediasize, sectorsize); if (opt_S) slogbench(fd, isreg, mediasize, sectorsize); out: close(fd); } free(buf); exit (exitval); +} + +static bool +candelete(int fd) +{ + struct diocgattr_arg arg; + + strlcpy(arg.name, "GEOM::candelete", sizeof(arg.name)); + arg.len = sizeof(arg.value.i); + if (ioctl(fd, DIOCGATTR, &arg) == 0) + return (arg.value.i != 0); + else + return (false); +} + +static void +rotationrate(int fd, char *rate, size_t buflen) +{ + struct diocgattr_arg arg; + int ret; + + strlcpy(arg.name, "GEOM::rotation_rate", sizeof(arg.name)); + arg.len = sizeof(arg.value.u16); + + ret = ioctl(fd, DIOCGATTR, &arg); + if (ret < 0 || arg.value.u16 == DISK_RR_UNKNOWN) + snprintf(rate, buflen, "Unknown"); + else if (arg.value.u16 == DISK_RR_NON_ROTATING) + snprintf(rate, buflen, "%d", 0); + else if (arg.value.u16 >= DISK_RR_MIN && arg.value.u16 <= DISK_RR_MAX) + snprintf(rate, buflen, "%d", arg.value.u16); + else + snprintf(rate, buflen, "Invalid"); } static void rdsect(int fd, off_t blockno, u_int sectorsize) { int error; if (lseek(fd, (off_t)blockno * sectorsize, SEEK_SET) == -1) err(1, "lseek"); error = read(fd, buf, sectorsize); if (error == -1) err(1, "read"); if (error != (int)sectorsize) errx(1, "disk too small for test."); } static void rdmega(int fd) { int error; error = read(fd, buf, MEGATX); if (error == -1) err(1, "read"); if (error != MEGATX) errx(1, "disk too small for test."); } static struct timeval tv1, tv2; static void T0(void) { fflush(stdout); sync(); sleep(1); sync(); sync(); gettimeofday(&tv1, NULL); } static double delta_t(void) { double dt; gettimeofday(&tv2, NULL); dt = (tv2.tv_usec - tv1.tv_usec) / 1e6; dt += (tv2.tv_sec - tv1.tv_sec); return (dt); } static void TN(int count) { double dt; dt = delta_t(); printf("%5d iter in %10.6f sec = %8.3f msec\n", count, dt, dt * 1000.0 / count); } static void TR(double count) { double dt; dt = delta_t(); printf("%8.0f kbytes in %10.6f sec = %8.0f kbytes/sec\n", count, dt, count / dt); } static void TI(double count) { double dt; dt = delta_t(); printf("%8.0f ops in %10.6f sec = %8.0f IOPS\n", count, dt, count / dt); } static void TS(u_int size, int count) { double dt; dt = delta_t(); printf("%8.1f usec/IO = %8.1f Mbytes/s\n", dt * 1000000.0 / count, size * count / dt / (1024 * 1024)); } static void speeddisk(int fd, off_t mediasize, u_int sectorsize) { int bulk, i; off_t b0, b1, sectorcount, step; sectorcount = mediasize / sectorsize; if (sectorcount <= 0) return; /* Can't test devices with no sectors */ step = 1ULL << (flsll(sectorcount / (4 * 200)) - 1); if (step > 16384) step = 16384; bulk = mediasize / (1024 * 1024); if (bulk > 100) bulk = 100; printf("Seek times:\n"); printf("\tFull stroke:\t"); b0 = 0; b1 = sectorcount - step; T0(); for (i = 0; i < 125; i++) { rdsect(fd, b0, sectorsize); b0 += step; rdsect(fd, b1, sectorsize); b1 -= step; } TN(250); printf("\tHalf stroke:\t"); b0 = sectorcount / 4; b1 = b0 + sectorcount / 2; T0(); for (i = 0; i < 125; i++) { rdsect(fd, b0, sectorsize); b0 += step; rdsect(fd, b1, sectorsize); b1 += step; } TN(250); printf("\tQuarter stroke:\t"); b0 = sectorcount / 4; b1 = b0 + sectorcount / 4; T0(); for (i = 0; i < 250; i++) { rdsect(fd, b0, sectorsize); b0 += step; rdsect(fd, b1, sectorsize); b1 += step; } TN(500); printf("\tShort forward:\t"); b0 = sectorcount / 2; T0(); for (i = 0; i < 400; i++) { rdsect(fd, b0, sectorsize); b0 += step; } TN(400); printf("\tShort backward:\t"); b0 = sectorcount / 2; T0(); for (i = 0; i < 400; i++) { rdsect(fd, b0, sectorsize); b0 -= step; } TN(400); printf("\tSeq outer:\t"); b0 = 0; T0(); for (i = 0; i < 2048; i++) { rdsect(fd, b0, sectorsize); b0++; } TN(2048); printf("\tSeq inner:\t"); b0 = sectorcount - 2048; T0(); for (i = 0; i < 2048; i++) { rdsect(fd, b0, sectorsize); b0++; } TN(2048); printf("\nTransfer rates:\n"); printf("\toutside: "); rdsect(fd, 0, sectorsize); T0(); for (i = 0; i < bulk; i++) { rdmega(fd); } TR(bulk * 1024); printf("\tmiddle: "); b0 = sectorcount / 2 - bulk * (1024*1024 / sectorsize) / 2 - 1; rdsect(fd, b0, sectorsize); T0(); for (i = 0; i < bulk; i++) { rdmega(fd); } TR(bulk * 1024); printf("\tinside: "); b0 = sectorcount - bulk * (1024*1024 / sectorsize) - 1; rdsect(fd, b0, sectorsize); T0(); for (i = 0; i < bulk; i++) { rdmega(fd); } TR(bulk * 1024); printf("\n"); return; } static void commandtime(int fd, off_t mediasize, u_int sectorsize) { double dtmega, dtsector; int i; printf("I/O command overhead:\n"); i = mediasize; rdsect(fd, 0, sectorsize); T0(); for (i = 0; i < 10; i++) rdmega(fd); dtmega = delta_t(); printf("\ttime to read 10MB block %10.6f sec\t= %8.3f msec/sector\n", dtmega, dtmega*100/2048); rdsect(fd, 0, sectorsize); T0(); for (i = 0; i < 20480; i++) rdsect(fd, 0, sectorsize); dtsector = delta_t(); printf("\ttime to read 20480 sectors %10.6f sec\t= %8.3f msec/sector\n", dtsector, dtsector*100/2048); printf("\tcalculated command overhead\t\t\t= %8.3f msec/sector\n", (dtsector - dtmega)*100/2048); printf("\n"); return; } static void iops(int fd, off_t mediasize, u_int sectorsize) { struct aiocb aios[NAIO], *aiop; ssize_t ret; off_t sectorcount; int error, i, queued, completed; sectorcount = mediasize / sectorsize; for (i = 0; i < NAIO; i++) { aiop = &(aios[i]); bzero(aiop, sizeof(*aiop)); aiop->aio_buf = malloc(sectorsize); if (aiop->aio_buf == NULL) err(1, "malloc"); } T0(); for (i = 0; i < NAIO; i++) { aiop = &(aios[i]); aiop->aio_fildes = fd; aiop->aio_offset = (random() % (sectorcount)) * sectorsize; aiop->aio_nbytes = sectorsize; error = aio_read(aiop); if (error != 0) err(1, "aio_read"); } queued = i; completed = 0; for (;;) { ret = aio_waitcomplete(&aiop, NULL); if (ret < 0) err(1, "aio_waitcomplete"); if (ret != (ssize_t)sectorsize) errx(1, "short read"); completed++; if (delta_t() < 3.0) { aiop->aio_fildes = fd; aiop->aio_offset = (random() % (sectorcount)) * sectorsize; aiop->aio_nbytes = sectorsize; error = aio_read(aiop); if (error != 0) err(1, "aio_read"); queued++; } else if (completed == queued) { break; } } TI(completed); return; } static void iopsbench(int fd, off_t mediasize, u_int sectorsize) { printf("Asynchronous random reads:\n"); printf("\tsectorsize: "); iops(fd, mediasize, sectorsize); if (sectorsize != 4096) { printf("\t4 kbytes: "); iops(fd, mediasize, 4096); } printf("\t32 kbytes: "); iops(fd, mediasize, 32 * 1024); printf("\t128 kbytes: "); iops(fd, mediasize, 128 * 1024); printf("\n"); } #define MAXIO (128*1024) #define MAXIOS (MAXTX / MAXIO) static void parwrite(int fd, size_t size, off_t off) { struct aiocb aios[MAXIOS]; off_t o; size_t s; int n, error; struct aiocb *aiop; for (n = 0, o = 0; size > MAXIO; n++, size -= s, o += s) { s = (size >= MAXIO) ? MAXIO : size; aiop = &aios[n]; bzero(aiop, sizeof(*aiop)); aiop->aio_buf = &buf[o]; aiop->aio_fildes = fd; aiop->aio_offset = off + o; aiop->aio_nbytes = s; error = aio_write(aiop); if (error != 0) err(EX_IOERR, "AIO write submit error"); } error = pwrite(fd, &buf[o], size, off + o); if (error < 0) err(EX_IOERR, "Sync write error"); for (; n > 0; n--) { error = aio_waitcomplete(&aiop, NULL); if (error < 0) err(EX_IOERR, "AIO write wait error"); } } static void slogbench(int fd, int isreg, off_t mediasize, u_int sectorsize) { off_t off; u_int size; int error, n, N, nowritecache = 0; printf("Synchronous random writes:\n"); for (size = sectorsize; size <= MAXTX; size *= 2) { printf("\t%4.4g kbytes: ", (double)size / 1024); N = 0; T0(); do { for (n = 0; n < 250; n++) { off = random() % (mediasize / size); parwrite(fd, size, off * size); if (nowritecache) continue; if (isreg) error = fsync(fd); else error = ioctl(fd, DIOCGFLUSH); if (error < 0) { if (errno == ENOTSUP) nowritecache = 1; else err(EX_IOERR, "Flush error"); } } N += 250; } while (delta_t() < 1.0); TS(size, N); } } static int zonecheck(int fd, uint32_t *zone_mode, char *zone_str, size_t zone_str_len) { struct disk_zone_args zone_args; int error; bzero(&zone_args, sizeof(zone_args)); zone_args.zone_cmd = DISK_ZONE_GET_PARAMS; error = ioctl(fd, DIOCZONECMD, &zone_args); if (error == 0) { *zone_mode = zone_args.zone_params.disk_params.zone_mode; switch (*zone_mode) { case DISK_ZONE_MODE_NONE: snprintf(zone_str, zone_str_len, "Not_Zoned"); break; case DISK_ZONE_MODE_HOST_AWARE: snprintf(zone_str, zone_str_len, "Host_Aware"); break; case DISK_ZONE_MODE_DRIVE_MANAGED: snprintf(zone_str, zone_str_len, "Drive_Managed"); break; case DISK_ZONE_MODE_HOST_MANAGED: snprintf(zone_str, zone_str_len, "Host_Managed"); break; default: snprintf(zone_str, zone_str_len, "Unknown_zone_mode_%u", *zone_mode); break; } } return (error); } Index: stable/11 =================================================================== --- stable/11 (revision 325002) +++ stable/11 (revision 325003) Property changes on: stable/11 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r324281