Finally... Import the latest open-source ZFS version - (SPA) 28.

Few new things available from now on:

- Data deduplication.
- Triple parity RAIDZ (RAIDZ3).
- zfs diff.
- zpool split.
- Snapshot holds.
- zpool import -F. Allows to rewind corrupted pool to earlier
  transaction group.
- Possibility to import pool in read-only mode.

MFC after:	1 month
This commit is contained in:
Pawel Jakub Dawidek 2011-02-27 19:41:40 +00:00
parent e02dd14a54
commit 10b9d77bf1
304 changed files with 59881 additions and 20297 deletions

View File

@ -32,6 +32,7 @@
#include_next <fcntl.h>
#define open64 open
#define open64(...) open(__VA_ARGS__)
#define openat64(...) openat(__VA_ARGS__)
#endif

View File

@ -12,6 +12,10 @@
#define MNTTAB _PATH_DEVZERO
#define MNT_LINE_MAX 1024
#define MS_OVERLAY 0x0
#define MS_NOMNTTAB 0x0
#define MS_RDONLY 0x1
#define umount2(p, f) unmount(p, f)
struct mnttab {

View File

@ -10,7 +10,7 @@
#define PRIV_SYS_CONFIG 0
static __inline int
priv_ineffect(priv)
priv_ineffect(int priv)
{
assert(priv == PRIV_SYS_CONFIG);

View File

@ -0,0 +1,38 @@
/*-
* Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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 _OPENSOLARIS_SHA2_H_
#define _OPENSOLARIS_SHA2_H_
#include_next <sha256.h>
#define SHA256Init(c) SHA256_Init(c)
#define SHA256Update(c, d, s) SHA256_Update((c), (d), (s))
#define SHA256Final(b, c) SHA256_Final((unsigned char *)(b), (c))
#endif /* !_OPENSOLARIS_SHA2_H_ */

View File

@ -5,6 +5,10 @@
#include <sys/ccompile.h>
#define dirent64 dirent
#include <fcntl.h>
#define NOTE(s)
int mkdirp(const char *, mode_t);
#endif /* !_SOLARIS_H_ */

View File

@ -0,0 +1,39 @@
/*-
* Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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 _OPENSOLARIS_THREAD_POOL_H_
#define _OPENSOLARIS_THREAD_POOL_H_
typedef int tpool_t;
#define tpool_create(a, b, c, d) (0)
#define tpool_dispatch(pool, func, arg) func(arg)
#define tpool_wait(pool) do { } while (0)
#define tpool_destroy(pool) do { } while (0)
#endif /* !_OPENSOLARIS_THREAD_POOL_H_ */

View File

@ -28,15 +28,17 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <libutil.h>
#include <assert.h>
#include <pathnames.h> /* _PATH_MOUNTDPID */
#include <errno.h>
#include <fcntl.h>
#include <fsshare.h>
#include <libutil.h>
#include <pathnames.h> /* _PATH_MOUNTDPID */
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define FILE_HEADER "# !!! DO NOT EDIT THIS FILE MANUALLY !!!\n\n"
#define OPTSSIZE 1024

View File

@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mnttab.h>
static void
build_iovec(struct iovec **iov, int *iovlen, const char *name, void *val,
@ -78,7 +79,7 @@ zmount(const char *spec, const char *dir, int mflag, char *fstype,
assert(spec != NULL);
assert(dir != NULL);
assert(mflag == 0);
assert(mflag == 0 || mflag == MS_RDONLY);
assert(fstype != NULL);
assert(strcmp(fstype, MNTTYPE_ZFS) == 0);
assert(dataptr == NULL);
@ -91,6 +92,8 @@ zmount(const char *spec, const char *dir, int mflag, char *fstype,
iov = NULL;
iovlen = 0;
if (mflag & MS_RDONLY)
build_iovec(&iov, &iovlen, "ro", NULL, 0);
build_iovec(&iov, &iovlen, "fstype", fstype, (size_t)-1);
build_iovec(&iov, &iovlen, "fspath", __DECONST(char *, dir),
(size_t)-1);

View File

@ -0,0 +1,50 @@
/*
* CDDL HEADER START
*
* 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]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
*
* Common routines for acquiring snapshots of kstats for
* iostat, mpstat, and vmstat.
*/
#ifndef _STATCOMMON_H
#define _STATCOMMON_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <sys/types.h>
#include <time.h>
#define NODATE 0 /* Default: No time stamp */
#define DDATE 1 /* Standard date format */
#define UDATE 2 /* Internal representation of Unix time */
/* Print a timestamp in either Unix or standard format. */
void print_timestamp(uint_t);
#ifdef __cplusplus
}
#endif
#endif /* _STATCOMMON_H */

View File

@ -0,0 +1,49 @@
/*
* CDDL HEADER START
*
* 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]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include "statcommon.h"
#include <langinfo.h>
/*
* Print timestamp as decimal reprentation of time_t value (-T u was specified)
* or in date(1) format (-T d was specified).
*/
void
print_timestamp(uint_t timestamp_fmt)
{
time_t t = time(NULL);
if (timestamp_fmt == UDATE) {
(void) printf("%ld\n", t);
} else if (timestamp_fmt == DDATE) {
char dstr[64];
int len;
len = strftime(dstr, sizeof (dstr), "%+", localtime(&t));
if (len > 0)
(void) printf("%s\n", dstr);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -40,12 +40,14 @@
extern uint8_t dump_opt[256];
static char prefix[4] = "\t\t\t";
static void
print_log_bp(const blkptr_t *bp, const char *prefix)
{
char blkbuf[BP_SPRINTF_LEN];
sprintf_blkptr(blkbuf, BP_SPRINTF_LEN, bp);
sprintf_blkptr(blkbuf, bp);
(void) printf("%s%s\n", prefix, blkbuf);
}
@ -54,19 +56,29 @@ static void
zil_prt_rec_create(zilog_t *zilog, int txtype, lr_create_t *lr)
{
time_t crtime = lr->lr_crtime[0];
char *name = (char *)(lr + 1);
char *link = name + strlen(name) + 1;
char *name, *link;
lr_attr_t *lrattr;
if (txtype == TX_SYMLINK)
(void) printf("\t\t\t%s -> %s\n", name, link);
else
(void) printf("\t\t\t%s\n", name);
name = (char *)(lr + 1);
(void) printf("\t\t\t%s", ctime(&crtime));
(void) printf("\t\t\tdoid %llu, foid %llu, mode %llo\n",
if (lr->lr_common.lrc_txtype == TX_CREATE_ATTR ||
lr->lr_common.lrc_txtype == TX_MKDIR_ATTR) {
lrattr = (lr_attr_t *)(lr + 1);
name += ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
}
if (txtype == TX_SYMLINK) {
link = name + strlen(name) + 1;
(void) printf("%s%s -> %s\n", prefix, name, link);
} else if (txtype != TX_MKXATTR) {
(void) printf("%s%s\n", prefix, name);
}
(void) printf("%s%s", prefix, ctime(&crtime));
(void) printf("%sdoid %llu, foid %llu, mode %llo\n", prefix,
(u_longlong_t)lr->lr_doid, (u_longlong_t)lr->lr_foid,
(longlong_t)lr->lr_mode);
(void) printf("\t\t\tuid %llu, gid %llu, gen %llu, rdev 0x%llx\n",
(void) printf("%suid %llu, gid %llu, gen %llu, rdev 0x%llx\n", prefix,
(u_longlong_t)lr->lr_uid, (u_longlong_t)lr->lr_gid,
(u_longlong_t)lr->lr_gen, (u_longlong_t)lr->lr_rdev);
}
@ -75,7 +87,7 @@ zil_prt_rec_create(zilog_t *zilog, int txtype, lr_create_t *lr)
static void
zil_prt_rec_remove(zilog_t *zilog, int txtype, lr_remove_t *lr)
{
(void) printf("\t\t\tdoid %llu, name %s\n",
(void) printf("%sdoid %llu, name %s\n", prefix,
(u_longlong_t)lr->lr_doid, (char *)(lr + 1));
}
@ -83,7 +95,7 @@ zil_prt_rec_remove(zilog_t *zilog, int txtype, lr_remove_t *lr)
static void
zil_prt_rec_link(zilog_t *zilog, int txtype, lr_link_t *lr)
{
(void) printf("\t\t\tdoid %llu, link_obj %llu, name %s\n",
(void) printf("%sdoid %llu, link_obj %llu, name %s\n", prefix,
(u_longlong_t)lr->lr_doid, (u_longlong_t)lr->lr_link_obj,
(char *)(lr + 1));
}
@ -95,9 +107,9 @@ zil_prt_rec_rename(zilog_t *zilog, int txtype, lr_rename_t *lr)
char *snm = (char *)(lr + 1);
char *tnm = snm + strlen(snm) + 1;
(void) printf("\t\t\tsdoid %llu, tdoid %llu\n",
(void) printf("%ssdoid %llu, tdoid %llu\n", prefix,
(u_longlong_t)lr->lr_sdoid, (u_longlong_t)lr->lr_tdoid);
(void) printf("\t\t\tsrc %s tgt %s\n", snm, tnm);
(void) printf("%ssrc %s tgt %s\n", prefix, snm, tnm);
}
/* ARGSUSED */
@ -106,44 +118,48 @@ zil_prt_rec_write(zilog_t *zilog, int txtype, lr_write_t *lr)
{
char *data, *dlimit;
blkptr_t *bp = &lr->lr_blkptr;
zbookmark_t zb;
char buf[SPA_MAXBLOCKSIZE];
int verbose = MAX(dump_opt['d'], dump_opt['i']);
int error;
(void) printf("\t\t\tfoid %llu, offset 0x%llx,"
" length 0x%llx, blkoff 0x%llx\n",
(u_longlong_t)lr->lr_foid, (longlong_t)lr->lr_offset,
(u_longlong_t)lr->lr_length, (u_longlong_t)lr->lr_blkoff);
(void) printf("%sfoid %llu, offset %llx, length %llx\n", prefix,
(u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_offset,
(u_longlong_t)lr->lr_length);
if (txtype == TX_WRITE2 || verbose < 5)
return;
if (lr->lr_common.lrc_reclen == sizeof (lr_write_t)) {
(void) printf("\t\t\thas blkptr, %s\n",
(void) printf("%shas blkptr, %s\n", prefix,
bp->blk_birth >= spa_first_txg(zilog->zl_spa) ?
"will claim" : "won't claim");
print_log_bp(bp, "\t\t\t");
print_log_bp(bp, prefix);
if (BP_IS_HOLE(bp)) {
(void) printf("\t\t\tLSIZE 0x%llx\n",
(u_longlong_t)BP_GET_LSIZE(bp));
}
if (bp->blk_birth == 0) {
bzero(buf, sizeof (buf));
} else {
zbookmark_t zb;
zb.zb_objset = dmu_objset_id(zilog->zl_os);
zb.zb_object = lr->lr_foid;
zb.zb_level = 0;
zb.zb_blkid = -1; /* unknown */
error = zio_wait(zio_read(NULL, zilog->zl_spa,
bp, buf, BP_GET_LSIZE(bp), NULL, NULL,
ZIO_PRIORITY_SYNC_READ, ZIO_FLAG_CANFAIL, &zb));
if (error)
return;
(void) printf("%s<hole>\n", prefix);
return;
}
data = buf + lr->lr_blkoff;
if (bp->blk_birth < zilog->zl_header->zh_claim_txg) {
(void) printf("%s<block already committed>\n", prefix);
return;
}
SET_BOOKMARK(&zb, dmu_objset_id(zilog->zl_os),
lr->lr_foid, ZB_ZIL_LEVEL,
lr->lr_offset / BP_GET_LSIZE(bp));
error = zio_wait(zio_read(NULL, zilog->zl_spa,
bp, buf, BP_GET_LSIZE(bp), NULL, NULL,
ZIO_PRIORITY_SYNC_READ, ZIO_FLAG_CANFAIL, &zb));
if (error)
return;
data = buf;
} else {
data = (char *)(lr + 1);
}
@ -151,7 +167,7 @@ zil_prt_rec_write(zilog_t *zilog, int txtype, lr_write_t *lr)
dlimit = data + MIN(lr->lr_length,
(verbose < 6 ? 20 : SPA_MAXBLOCKSIZE));
(void) printf("\t\t\t");
(void) printf("%s", prefix);
while (data < dlimit) {
if (isprint(*data))
(void) printf("%c ", *data);
@ -166,7 +182,7 @@ zil_prt_rec_write(zilog_t *zilog, int txtype, lr_write_t *lr)
static void
zil_prt_rec_truncate(zilog_t *zilog, int txtype, lr_truncate_t *lr)
{
(void) printf("\t\t\tfoid %llu, offset 0x%llx, length 0x%llx\n",
(void) printf("%sfoid %llu, offset 0x%llx, length 0x%llx\n", prefix,
(u_longlong_t)lr->lr_foid, (longlong_t)lr->lr_offset,
(u_longlong_t)lr->lr_length);
}
@ -178,38 +194,38 @@ zil_prt_rec_setattr(zilog_t *zilog, int txtype, lr_setattr_t *lr)
time_t atime = (time_t)lr->lr_atime[0];
time_t mtime = (time_t)lr->lr_mtime[0];
(void) printf("\t\t\tfoid %llu, mask 0x%llx\n",
(void) printf("%sfoid %llu, mask 0x%llx\n", prefix,
(u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_mask);
if (lr->lr_mask & AT_MODE) {
(void) printf("\t\t\tAT_MODE %llo\n",
(void) printf("%sAT_MODE %llo\n", prefix,
(longlong_t)lr->lr_mode);
}
if (lr->lr_mask & AT_UID) {
(void) printf("\t\t\tAT_UID %llu\n",
(void) printf("%sAT_UID %llu\n", prefix,
(u_longlong_t)lr->lr_uid);
}
if (lr->lr_mask & AT_GID) {
(void) printf("\t\t\tAT_GID %llu\n",
(void) printf("%sAT_GID %llu\n", prefix,
(u_longlong_t)lr->lr_gid);
}
if (lr->lr_mask & AT_SIZE) {
(void) printf("\t\t\tAT_SIZE %llu\n",
(void) printf("%sAT_SIZE %llu\n", prefix,
(u_longlong_t)lr->lr_size);
}
if (lr->lr_mask & AT_ATIME) {
(void) printf("\t\t\tAT_ATIME %llu.%09llu %s",
(void) printf("%sAT_ATIME %llu.%09llu %s", prefix,
(u_longlong_t)lr->lr_atime[0],
(u_longlong_t)lr->lr_atime[1],
ctime(&atime));
}
if (lr->lr_mask & AT_MTIME) {
(void) printf("\t\t\tAT_MTIME %llu.%09llu %s",
(void) printf("%sAT_MTIME %llu.%09llu %s", prefix,
(u_longlong_t)lr->lr_mtime[0],
(u_longlong_t)lr->lr_mtime[1],
ctime(&mtime));
@ -220,7 +236,7 @@ zil_prt_rec_setattr(zilog_t *zilog, int txtype, lr_setattr_t *lr)
static void
zil_prt_rec_acl(zilog_t *zilog, int txtype, lr_acl_t *lr)
{
(void) printf("\t\t\tfoid %llu, aclcnt %llu\n",
(void) printf("%sfoid %llu, aclcnt %llu\n", prefix,
(u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_aclcnt);
}
@ -256,7 +272,7 @@ static zil_rec_info_t zil_rec_info[TX_MAX_TYPE] = {
};
/* ARGSUSED */
static void
static int
print_log_record(zilog_t *zilog, lr_t *lr, void *arg, uint64_t claim_txg)
{
int txtype;
@ -280,23 +296,24 @@ print_log_record(zilog_t *zilog, lr_t *lr, void *arg, uint64_t claim_txg)
zil_rec_info[txtype].zri_count++;
zil_rec_info[0].zri_count++;
return (0);
}
/* ARGSUSED */
static void
static int
print_log_block(zilog_t *zilog, blkptr_t *bp, void *arg, uint64_t claim_txg)
{
char blkbuf[BP_SPRINTF_LEN];
char blkbuf[BP_SPRINTF_LEN + 10];
int verbose = MAX(dump_opt['d'], dump_opt['i']);
char *claim;
if (verbose <= 3)
return;
return (0);
if (verbose >= 5) {
(void) strcpy(blkbuf, ", ");
sprintf_blkptr(blkbuf + strlen(blkbuf),
BP_SPRINTF_LEN - strlen(blkbuf), bp);
sprintf_blkptr(blkbuf + strlen(blkbuf), bp);
} else {
blkbuf[0] = '\0';
}
@ -310,6 +327,8 @@ print_log_block(zilog_t *zilog, blkptr_t *bp, void *arg, uint64_t claim_txg)
(void) printf("\tBlock seqno %llu, %s%s\n",
(u_longlong_t)bp->blk_cksum.zc_word[ZIL_ZC_SEQ], claim, blkbuf);
return (0);
}
static void
@ -342,17 +361,17 @@ dump_intent_log(zilog_t *zilog)
int verbose = MAX(dump_opt['d'], dump_opt['i']);
int i;
if (zh->zh_log.blk_birth == 0 || verbose < 2)
if (zh->zh_log.blk_birth == 0 || verbose < 1)
return;
(void) printf("\n ZIL header: claim_txg %llu, claim_seq %llu",
(u_longlong_t)zh->zh_claim_txg, (u_longlong_t)zh->zh_claim_seq);
(void) printf("\n ZIL header: claim_txg %llu, "
"claim_blk_seq %llu, claim_lr_seq %llu",
(u_longlong_t)zh->zh_claim_txg,
(u_longlong_t)zh->zh_claim_blk_seq,
(u_longlong_t)zh->zh_claim_lr_seq);
(void) printf(" replay_seq %llu, flags 0x%llx\n",
(u_longlong_t)zh->zh_replay_seq, (u_longlong_t)zh->zh_flags);
if (verbose >= 4)
print_log_bp(&zh->zh_log, "\n\tfirst block: ");
for (i = 0; i < TX_MAX_TYPE; i++)
zil_rec_info[i].zri_count = 0;

File diff suppressed because it is too large Load Diff

View File

@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <libintl.h>
@ -107,7 +106,8 @@ zfs_callback(zfs_handle_t *zhp, void *data)
zfs_prune_proplist(zhp,
cb->cb_props_table);
if (zfs_expand_proplist(zhp, cb->cb_proplist)
if (zfs_expand_proplist(zhp, cb->cb_proplist,
(cb->cb_flags & ZFS_ITER_RECVD_PROPS))
!= 0) {
free(node);
return (-1);
@ -350,11 +350,8 @@ zfs_for_each(int argc, char **argv, int flags, zfs_type_t types,
avl_pool = uu_avl_pool_create("zfs_pool", sizeof (zfs_node_t),
offsetof(zfs_node_t, zn_avlnode), zfs_sort, UU_DEFAULT);
if (avl_pool == NULL) {
(void) fprintf(stderr,
gettext("internal error: out of memory\n"));
exit(1);
}
if (avl_pool == NULL)
nomem();
cb.cb_sortcol = sortcol;
cb.cb_flags = flags;
@ -362,7 +359,7 @@ zfs_for_each(int argc, char **argv, int flags, zfs_type_t types,
cb.cb_types = types;
cb.cb_depth_limit = limit;
/*
* If cb_proplist is provided then in the zfs_handles created we
* If cb_proplist is provided then in the zfs_handles created we
* retain only those properties listed in cb_proplist and sortcol.
* The rest are pruned. So, the caller should make sure that no other
* properties other than those listed in cb_proplist/sortcol are
@ -399,11 +396,8 @@ zfs_for_each(int argc, char **argv, int flags, zfs_type_t types,
sizeof (cb.cb_props_table));
}
if ((cb.cb_avl = uu_avl_create(avl_pool, NULL, UU_DEFAULT)) == NULL) {
(void) fprintf(stderr,
gettext("internal error: out of memory\n"));
exit(1);
}
if ((cb.cb_avl = uu_avl_create(avl_pool, NULL, UU_DEFAULT)) == NULL)
nomem();
if (argc == 0) {
/*
@ -453,11 +447,8 @@ zfs_for_each(int argc, char **argv, int flags, zfs_type_t types,
/*
* Finally, clean up the AVL tree.
*/
if ((walk = uu_avl_walk_start(cb.cb_avl, UU_WALK_ROBUST)) == NULL) {
(void) fprintf(stderr,
gettext("internal error: out of memory"));
exit(1);
}
if ((walk = uu_avl_walk_start(cb.cb_avl, UU_WALK_ROBUST)) == NULL)
nomem();
while ((node = uu_avl_walk_next(walk)) != NULL) {
uu_avl_remove(cb.cb_avl, node);

View File

@ -42,6 +42,7 @@ typedef struct zfs_sort_column {
#define ZFS_ITER_ARGS_CAN_BE_PATHS (1 << 1)
#define ZFS_ITER_PROP_LISTSNAPS (1 << 2)
#define ZFS_ITER_DEPTH_LIMIT (1 << 3)
#define ZFS_ITER_RECVD_PROPS (1 << 4)
int zfs_for_each(int, char **, int options, zfs_type_t,
zfs_sort_column_t *, zprop_list_t **, int, zfs_iter_f, void *);

File diff suppressed because it is too large Load Diff

View File

@ -19,15 +19,12 @@
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _ZFS_UTIL_H
#define _ZFS_UTIL_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <libzfs.h>
#ifdef __cplusplus
@ -35,6 +32,7 @@ extern "C" {
#endif
void * safe_malloc(size_t size);
void nomem(void);
libzfs_handle_t *g_zfs;
#ifdef __cplusplus

View File

@ -19,14 +19,11 @@
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <libzfs.h>
#undef verify /* both libzfs.h and zfs_context.h want to define this */
#include <sys/zfs_context.h>
#include <errno.h>
@ -49,9 +46,6 @@
#include "zinject.h"
#include <assert.h>
#define verify assert
extern void kernel_init(int);
extern void kernel_fini(void);
@ -70,6 +64,18 @@ ziprintf(const char *fmt, ...)
va_end(ap);
}
static void
compress_slashes(const char *src, char *dest)
{
while (*src != '\0') {
*dest = *src++;
while (*dest == '/' && *src == '/')
++src;
++dest;
}
*dest = '\0';
}
/*
* Given a full path to a file, translate into a dataset name and a relative
* path within the dataset. 'dataset' must be at least MAXNAMELEN characters,
@ -77,11 +83,14 @@ ziprintf(const char *fmt, ...)
* buffer, which we need later to get the object ID.
*/
static int
parse_pathname(const char *fullpath, char *dataset, char *relpath,
parse_pathname(const char *inpath, char *dataset, char *relpath,
struct stat64 *statbuf)
{
struct statfs sfs;
const char *rel;
char fullpath[MAXPATHLEN];
compress_slashes(inpath, fullpath);
if (fullpath[0] != '/') {
(void) fprintf(stderr, "invalid object '%s': must be full "
@ -148,8 +157,8 @@ object_from_path(const char *dataset, const char *path, struct stat64 *statbuf,
*/
sync();
if ((err = dmu_objset_open(dataset, DMU_OST_ZFS,
DS_MODE_USER | DS_MODE_READONLY, &os)) != 0) {
err = dmu_objset_own(dataset, DMU_OST_ZFS, B_TRUE, FTAG, &os);
if (err != 0) {
(void) fprintf(stderr, "cannot open dataset '%s': %s\n",
dataset, strerror(err));
return (-1);
@ -158,7 +167,7 @@ object_from_path(const char *dataset, const char *path, struct stat64 *statbuf,
record->zi_objset = dmu_objset_id(os);
record->zi_object = statbuf->st_ino;
dmu_objset_close(os);
dmu_objset_disown(os, FTAG);
return (0);
}
@ -233,17 +242,17 @@ calculate_range(const char *dataset, err_type_t type, int level, char *range,
* Get the dnode associated with object, so we can calculate the block
* size.
*/
if ((err = dmu_objset_open(dataset, DMU_OST_ANY,
DS_MODE_USER | DS_MODE_READONLY, &os)) != 0) {
if ((err = dmu_objset_own(dataset, DMU_OST_ANY,
B_TRUE, FTAG, &os)) != 0) {
(void) fprintf(stderr, "cannot open dataset '%s': %s\n",
dataset, strerror(err));
goto out;
}
if (record->zi_object == 0) {
dn = os->os->os_meta_dnode;
dn = DMU_META_DNODE(os);
} else {
err = dnode_hold(os->os, record->zi_object, FTAG, &dn);
err = dnode_hold(os, record->zi_object, FTAG, &dn);
if (err != 0) {
(void) fprintf(stderr, "failed to hold dnode "
"for object %llu\n",
@ -292,11 +301,11 @@ calculate_range(const char *dataset, err_type_t type, int level, char *range,
ret = 0;
out:
if (dn) {
if (dn != os->os->os_meta_dnode)
if (dn != DMU_META_DNODE(os))
dnode_rele(dn, FTAG);
}
if (os)
dmu_objset_close(os);
dmu_objset_disown(os, FTAG);
return (ret);
}
@ -333,8 +342,8 @@ translate_record(err_type_t type, const char *object, const char *range,
case TYPE_CONFIG:
record->zi_type = DMU_OT_PACKED_NVLIST;
break;
case TYPE_BPLIST:
record->zi_type = DMU_OT_BPLIST;
case TYPE_BPOBJ:
record->zi_type = DMU_OT_BPOBJ;
break;
case TYPE_SPACEMAP:
record->zi_type = DMU_OT_SPACE_MAP;
@ -455,6 +464,14 @@ translate_device(const char *pool, const char *device, err_type_t label_type,
record->zi_start = offsetof(vdev_label_t, vl_vdev_phys);
record->zi_end = record->zi_start + VDEV_PHYS_SIZE - 1;
break;
case TYPE_LABEL_PAD1:
record->zi_start = offsetof(vdev_label_t, vl_pad1);
record->zi_end = record->zi_start + VDEV_PAD_SIZE - 1;
break;
case TYPE_LABEL_PAD2:
record->zi_start = offsetof(vdev_label_t, vl_pad2);
record->zi_end = record->zi_start + VDEV_PAD_SIZE - 1;
break;
}
return (0);
}

View File

@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@ -42,12 +41,12 @@
* any attempt to read from the device will return EIO, but any attempt to
* reopen the device will also return ENXIO.
* For label faults, the -L option must be specified. This allows faults
* to be injected into either the nvlist or uberblock region of all the labels
* for the specified device.
* to be injected into either the nvlist, uberblock, pad1, or pad2 region
* of all the labels for the specified device.
*
* This form of the command looks like:
*
* zinject -d device [-e errno] [-L <uber | nvlist>] pool
* zinject -d device [-e errno] [-L <uber | nvlist | pad1 | pad2>] pool
*
*
* DATA FAULTS
@ -70,7 +69,7 @@
* mos Any data in the MOS
* mosdir object directory
* config pool configuration
* bplist blkptr list
* bpobj blkptr list
* spacemap spacemap
* metaslab metaslab
* errlog persistent error log
@ -167,11 +166,13 @@ static const char *errtable[TYPE_INVAL] = {
"mosdir",
"metaslab",
"config",
"bplist",
"bpobj",
"spacemap",
"errlog",
"uber",
"nvlist"
"nvlist",
"pad1",
"pad2"
};
static err_type_t
@ -195,8 +196,8 @@ type_to_name(uint64_t type)
return ("metaslab");
case DMU_OT_PACKED_NVLIST:
return ("config");
case DMU_OT_BPLIST:
return ("bplist");
case DMU_OT_BPOBJ:
return ("bpobj");
case DMU_OT_SPACE_MAP:
return ("spacemap");
case DMU_OT_ERROR_LOG:
@ -225,10 +226,27 @@ usage(void)
"\t\tClear the particular record (if given a numeric ID), or\n"
"\t\tall records if 'all' is specificed.\n"
"\n"
"\tzinject -d device [-e errno] [-L <nvlist|uber>] [-F] pool\n"
"\tzinject -p <function name> pool\n"
"\t\tInject a panic fault at the specified function. Only \n"
"\t\tfunctions which call spa_vdev_config_exit(), or \n"
"\t\tspa_vdev_exit() will trigger a panic.\n"
"\n"
"\tzinject -d device [-e errno] [-L <nvlist|uber|pad1|pad2>] [-F]\n"
"\t [-T <read|write|free|claim|all> pool\n"
"\t\tInject a fault into a particular device or the device's\n"
"\t\tlabel. Label injection can either be 'nvlist' or 'uber'.\n"
"\t\t'errno' can either be 'nxio' (the default) or 'io'.\n"
"\t\tlabel. Label injection can either be 'nvlist', 'uber',\n "
"\t\t'pad1', or 'pad2'.\n"
"\t\t'errno' can be 'nxio' (the default), 'io', or 'dtl'.\n"
"\n"
"\tzinject -d device -A <degrade|fault> pool\n"
"\t\tPerform a specific action on a particular device\n"
"\n"
"\tzinject -I [-s <seconds> | -g <txgs>] pool\n"
"\t\tCause the pool to stop writing blocks yet not\n"
"\t\treport errors for a duration. Simulates buggy hardware\n"
"\t\tthat fails to honor cache flush requests.\n"
"\t\tDefault duration is 30 seconds. The machine is panicked\n"
"\t\tat the end of the duration.\n"
"\n"
"\tzinject -b objset:object:level:blkid pool\n"
"\n"
@ -270,7 +288,7 @@ usage(void)
"\t\t\ton a ZFS filesystem.\n"
"\n"
"\t-t <mos>\tInject errors into the MOS for objects of the given\n"
"\t\t\ttype. Valid types are: mos, mosdir, config, bplist,\n"
"\t\t\ttype. Valid types are: mos, mosdir, config, bpobj,\n"
"\t\t\tspacemap, metaslab, errlog. The only valid <object> is\n"
"\t\t\tthe poolname.\n");
}
@ -289,6 +307,12 @@ iter_handlers(int (*func)(int, const char *, zinject_record_t *, void *),
&zc.zc_inject_record, data)) != 0)
return (ret);
if (errno != ENOENT) {
(void) fprintf(stderr, "Unable to list handlers: %s\n",
strerror(errno));
return (-1);
}
return (0);
}
@ -298,7 +322,7 @@ print_data_handler(int id, const char *pool, zinject_record_t *record,
{
int *count = data;
if (record->zi_guid != 0)
if (record->zi_guid != 0 || record->zi_func[0] != '\0')
return (0);
if (*count == 0) {
@ -330,7 +354,7 @@ print_device_handler(int id, const char *pool, zinject_record_t *record,
{
int *count = data;
if (record->zi_guid == 0)
if (record->zi_guid == 0 || record->zi_func[0] != '\0')
return (0);
if (*count == 0) {
@ -346,6 +370,27 @@ print_device_handler(int id, const char *pool, zinject_record_t *record,
return (0);
}
static int
print_panic_handler(int id, const char *pool, zinject_record_t *record,
void *data)
{
int *count = data;
if (record->zi_func[0] == '\0')
return (0);
if (*count == 0) {
(void) printf("%3s %-15s %s\n", "ID", "POOL", "FUNCTION");
(void) printf("--- --------------- ----------------\n");
}
*count += 1;
(void) printf("%3d %-15s %s\n", id, pool, record->zi_func);
return (0);
}
/*
* Print all registered error handlers. Returns the number of handlers
* registered.
@ -353,14 +398,25 @@ print_device_handler(int id, const char *pool, zinject_record_t *record,
static int
print_all_handlers(void)
{
int count = 0;
int count = 0, total = 0;
(void) iter_handlers(print_device_handler, &count);
(void) printf("\n");
count = 0;
(void) iter_handlers(print_data_handler, &count);
if (count > 0) {
total += count;
(void) printf("\n");
count = 0;
}
return (count);
(void) iter_handlers(print_data_handler, &count);
if (count > 0) {
total += count;
(void) printf("\n");
count = 0;
}
(void) iter_handlers(print_panic_handler, &count);
return (count + total);
}
/* ARGSUSED */
@ -389,7 +445,8 @@ cancel_all_handlers(void)
{
int ret = iter_handlers(cancel_one_handler, NULL);
(void) printf("removed all registered handlers\n");
if (ret == 0)
(void) printf("removed all registered handlers\n");
return (ret);
}
@ -446,6 +503,15 @@ register_handler(const char *pool, int flags, zinject_record_t *record,
if (record->zi_guid) {
(void) printf(" vdev: %llx\n",
(u_longlong_t)record->zi_guid);
} else if (record->zi_func[0] != '\0') {
(void) printf(" panic function: %s\n",
record->zi_func);
} else if (record->zi_duration > 0) {
(void) printf(" time: %lld seconds\n",
(u_longlong_t)record->zi_duration);
} else if (record->zi_duration < 0) {
(void) printf(" txgs: %lld \n",
(u_longlong_t)-record->zi_duration);
} else {
(void) printf("objset: %llu\n",
(u_longlong_t)record->zi_objset);
@ -467,6 +533,22 @@ register_handler(const char *pool, int flags, zinject_record_t *record,
return (0);
}
int
perform_action(const char *pool, zinject_record_t *record, int cmd)
{
zfs_cmd_t zc;
ASSERT(cmd == VDEV_STATE_DEGRADED || cmd == VDEV_STATE_FAULTED);
(void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
zc.zc_guid = record->zi_guid;
zc.zc_cookie = cmd;
if (ioctl(zfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
return (0);
return (1);
}
int
main(int argc, char **argv)
{
@ -480,12 +562,17 @@ main(int argc, char **argv)
int quiet = 0;
int error = 0;
int domount = 0;
int io_type = ZIO_TYPES;
int action = VDEV_STATE_UNKNOWN;
err_type_t type = TYPE_INVAL;
err_type_t label = TYPE_INVAL;
zinject_record_t record = { 0 };
char pool[MAXNAMELEN];
char dataset[MAXNAMELEN];
zfs_handle_t *zhp;
int nowrites = 0;
int dur_txg = 0;
int dur_secs = 0;
int ret;
int flags = 0;
@ -517,11 +604,24 @@ main(int argc, char **argv)
return (0);
}
while ((c = getopt(argc, argv, ":ab:d:f:Fqhc:t:l:mr:e:uL:")) != -1) {
while ((c = getopt(argc, argv,
":aA:b:d:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:")) != -1) {
switch (c) {
case 'a':
flags |= ZINJECT_FLUSH_ARC;
break;
case 'A':
if (strcasecmp(optarg, "degrade") == 0) {
action = VDEV_STATE_DEGRADED;
} else if (strcasecmp(optarg, "fault") == 0) {
action = VDEV_STATE_FAULTED;
} else {
(void) fprintf(stderr, "invalid action '%s': "
"must be 'degrade' or 'fault'\n", optarg);
usage();
return (1);
}
break;
case 'b':
raw = optarg;
break;
@ -538,6 +638,8 @@ main(int argc, char **argv)
error = ECKSUM;
} else if (strcasecmp(optarg, "nxio") == 0) {
error = ENXIO;
} else if (strcasecmp(optarg, "dtl") == 0) {
error = ECHILD;
} else {
(void) fprintf(stderr, "invalid error type "
"'%s': must be 'io', 'checksum' or "
@ -557,9 +659,27 @@ main(int argc, char **argv)
case 'F':
record.zi_failfast = B_TRUE;
break;
case 'g':
dur_txg = 1;
record.zi_duration = (int)strtol(optarg, &end, 10);
if (record.zi_duration <= 0 || *end != '\0') {
(void) fprintf(stderr, "invalid duration '%s': "
"must be a positive integer\n", optarg);
usage();
return (1);
}
/* store duration of txgs as its negative */
record.zi_duration *= -1;
break;
case 'h':
usage();
return (0);
case 'I':
/* default duration, if one hasn't yet been defined */
nowrites = 1;
if (dur_secs == 0 && dur_txg == 0)
record.zi_duration = 30;
break;
case 'l':
level = (int)strtol(optarg, &end, 10);
if (*end != '\0') {
@ -572,12 +692,45 @@ main(int argc, char **argv)
case 'm':
domount = 1;
break;
case 'p':
(void) strlcpy(record.zi_func, optarg,
sizeof (record.zi_func));
break;
case 'q':
quiet = 1;
break;
case 'r':
range = optarg;
break;
case 's':
dur_secs = 1;
record.zi_duration = (int)strtol(optarg, &end, 10);
if (record.zi_duration <= 0 || *end != '\0') {
(void) fprintf(stderr, "invalid duration '%s': "
"must be a positive integer\n", optarg);
usage();
return (1);
}
break;
case 'T':
if (strcasecmp(optarg, "read") == 0) {
io_type = ZIO_TYPE_READ;
} else if (strcasecmp(optarg, "write") == 0) {
io_type = ZIO_TYPE_WRITE;
} else if (strcasecmp(optarg, "free") == 0) {
io_type = ZIO_TYPE_FREE;
} else if (strcasecmp(optarg, "claim") == 0) {
io_type = ZIO_TYPE_CLAIM;
} else if (strcasecmp(optarg, "all") == 0) {
io_type = ZIO_TYPES;
} else {
(void) fprintf(stderr, "invalid I/O type "
"'%s': must be 'read', 'write', 'free', "
"'claim' or 'all'\n", optarg);
usage();
return (1);
}
break;
case 't':
if ((type = name_to_type(optarg)) == TYPE_INVAL &&
!MOS_TYPE(type)) {
@ -620,7 +773,8 @@ main(int argc, char **argv)
* '-c' is invalid with any other options.
*/
if (raw != NULL || range != NULL || type != TYPE_INVAL ||
level != 0) {
level != 0 || record.zi_func[0] != '\0' ||
record.zi_duration != 0) {
(void) fprintf(stderr, "cancel (-c) incompatible with "
"any other options\n");
usage();
@ -652,7 +806,8 @@ main(int argc, char **argv)
* for doing injection, so handle it separately here.
*/
if (raw != NULL || range != NULL || type != TYPE_INVAL ||
level != 0) {
level != 0 || record.zi_func[0] != '\0' ||
record.zi_duration != 0) {
(void) fprintf(stderr, "device (-d) incompatible with "
"data error injection\n");
usage();
@ -675,12 +830,18 @@ main(int argc, char **argv)
return (1);
}
record.zi_iotype = io_type;
if (translate_device(pool, device, label, &record) != 0)
return (1);
if (!error)
error = ENXIO;
if (action != VDEV_STATE_UNKNOWN)
return (perform_action(pool, &record, action));
} else if (raw != NULL) {
if (range != NULL || type != TYPE_INVAL || level != 0) {
if (range != NULL || type != TYPE_INVAL || level != 0 ||
record.zi_func[0] != '\0' || record.zi_duration != 0) {
(void) fprintf(stderr, "raw (-b) format with "
"any other options\n");
usage();
@ -707,10 +868,52 @@ main(int argc, char **argv)
return (1);
if (!error)
error = EIO;
} else if (record.zi_func[0] != '\0') {
if (raw != NULL || range != NULL || type != TYPE_INVAL ||
level != 0 || device != NULL || record.zi_duration != 0) {
(void) fprintf(stderr, "panic (-p) incompatible with "
"other options\n");
usage();
return (2);
}
if (argc < 1 || argc > 2) {
(void) fprintf(stderr, "panic (-p) injection requires "
"a single pool name and an optional id\n");
usage();
return (2);
}
(void) strcpy(pool, argv[0]);
if (argv[1] != NULL)
record.zi_type = atoi(argv[1]);
dataset[0] = '\0';
} else if (record.zi_duration != 0) {
if (nowrites == 0) {
(void) fprintf(stderr, "-s or -g meaningless "
"without -I (ignore writes)\n");
usage();
return (2);
} else if (dur_secs && dur_txg) {
(void) fprintf(stderr, "choose a duration either "
"in seconds (-s) or a number of txgs (-g) "
"but not both\n");
usage();
return (2);
} else if (argc != 1) {
(void) fprintf(stderr, "ignore writes (-I) "
"injection requires a single pool name\n");
usage();
return (2);
}
(void) strcpy(pool, argv[0]);
dataset[0] = '\0';
} else if (type == TYPE_INVAL) {
if (flags == 0) {
(void) fprintf(stderr, "at least one of '-b', '-d', "
"'-t', '-a', or '-u' must be specified\n");
"'-t', '-a', '-p', '-I' or '-u' "
"must be specified\n");
usage();
return (2);
}

View File

@ -19,15 +19,12 @@
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _ZINJECT_H
#define _ZINJECT_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/zfs_ioctl.h>
#ifdef __cplusplus
@ -41,11 +38,13 @@ typedef enum {
TYPE_MOSDIR, /* MOS object directory */
TYPE_METASLAB, /* metaslab objects */
TYPE_CONFIG, /* MOS config */
TYPE_BPLIST, /* block pointer list */
TYPE_BPOBJ, /* block pointer list */
TYPE_SPACEMAP, /* space map objects */
TYPE_ERRLOG, /* persistent error log */
TYPE_LABEL_UBERBLOCK, /* label specific uberblock */
TYPE_LABEL_NVLIST, /* label specific nvlist */
TYPE_LABEL_PAD1, /* label specific 8K pad1 area */
TYPE_LABEL_PAD2, /* label specific 8K pad2 area */
TYPE_INVAL
} err_type_t;

View File

@ -0,0 +1,411 @@
/*
* CDDL HEADER START
*
* 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]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
* This is a test program that uses ioctls to the ZFS Unit Test driver
* to perform readdirs or lookups using flags not normally available
* to user-land programs. This allows testing of the flags'
* behavior outside of a complicated consumer, such as the SMB driver.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stropts.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/dirent.h>
#include <sys/attr.h>
#include <stddef.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#define _KERNEL
#include <sys/fs/zut.h>
#include <sys/extdirent.h>
#undef _KERNEL
#define MAXBUF (64 * 1024)
#define BIGBUF 4096
#define LILBUF (sizeof (dirent_t))
#define DIRENT_NAMELEN(reclen) \
((reclen) - (offsetof(dirent_t, d_name[0])))
static void
usage(char *pnam)
{
(void) fprintf(stderr, "Usage:\n %s -l [-is] dir-to-look-in "
"file-in-dir [xfile-on-file]\n", pnam);
(void) fprintf(stderr, " %s -i [-ls] dir-to-look-in "
"file-in-dir [xfile-on-file]\n", pnam);
(void) fprintf(stderr, " %s -s [-il] dir-to-look-in "
"file-in-dir [xfile-on-file]\n", pnam);
(void) fprintf(stderr, "\t Perform a lookup\n");
(void) fprintf(stderr, "\t -l == lookup\n");
(void) fprintf(stderr, "\t -i == request FIGNORECASE\n");
(void) fprintf(stderr, "\t -s == request stat(2) and xvattr info\n");
(void) fprintf(stderr, " %s -r [-ea] [-b buffer-size-in-bytes] "
"dir-to-look-in [file-in-dir]\n", pnam);
(void) fprintf(stderr, " %s -e [-ra] [-b buffer-size-in-bytes] "
"dir-to-look-in [file-in-dir]\n", pnam);
(void) fprintf(stderr, " %s -a [-re] [-b buffer-size-in-bytes] "
"dir-to-look-in [file-in-dir]\n", pnam);
(void) fprintf(stderr, "\t Perform a readdir\n");
(void) fprintf(stderr, "\t -r == readdir\n");
(void) fprintf(stderr, "\t -e == request extended entries\n");
(void) fprintf(stderr, "\t -a == request access filtering\n");
(void) fprintf(stderr, "\t -b == buffer size (default 4K)\n");
(void) fprintf(stderr, " %s -A path\n", pnam);
(void) fprintf(stderr, "\t Look up _PC_ACCESS_FILTERING "
"for path with pathconf(2)\n");
(void) fprintf(stderr, " %s -E path\n", pnam);
(void) fprintf(stderr, "\t Look up _PC_SATTR_EXISTS "
"for path with pathconf(2)\n");
(void) fprintf(stderr, " %s -S path\n", pnam);
(void) fprintf(stderr, "\t Look up _PC_SATTR_EXISTS "
"for path with pathconf(2)\n");
exit(EINVAL);
}
static void
print_extd_entries(zut_readdir_t *r)
{
struct edirent *eodp;
char *bufstart;
eodp = (edirent_t *)(uintptr_t)r->zr_buf;
bufstart = (char *)eodp;
while ((char *)eodp < bufstart + r->zr_bytes) {
char *blanks = " ";
int i = 0;
while (i < EDIRENT_NAMELEN(eodp->ed_reclen)) {
if (!eodp->ed_name[i])
break;
(void) printf("%c", eodp->ed_name[i++]);
}
if (i < 16)
(void) printf("%.*s", 16 - i, blanks);
(void) printf("\t%x\n", eodp->ed_eflags);
eodp = (edirent_t *)((intptr_t)eodp + eodp->ed_reclen);
}
}
static void
print_entries(zut_readdir_t *r)
{
dirent64_t *dp;
char *bufstart;
dp = (dirent64_t *)(intptr_t)r->zr_buf;
bufstart = (char *)dp;
while ((char *)dp < bufstart + r->zr_bytes) {
int i = 0;
while (i < DIRENT_NAMELEN(dp->d_reclen)) {
if (!dp->d_name[i])
break;
(void) printf("%c", dp->d_name[i++]);
}
(void) printf("\n");
dp = (dirent64_t *)((intptr_t)dp + dp->d_reclen);
}
}
static void
print_stats(struct stat64 *sb)
{
char timebuf[512];
(void) printf("st_mode\t\t\t%04lo\n", (unsigned long)sb->st_mode);
(void) printf("st_ino\t\t\t%llu\n", (unsigned long long)sb->st_ino);
(void) printf("st_nlink\t\t%lu\n", (unsigned long)sb->st_nlink);
(void) printf("st_uid\t\t\t%d\n", sb->st_uid);
(void) printf("st_gid\t\t\t%d\n", sb->st_gid);
(void) printf("st_size\t\t\t%lld\n", (long long)sb->st_size);
(void) printf("st_blksize\t\t%ld\n", (long)sb->st_blksize);
(void) printf("st_blocks\t\t%lld\n", (long long)sb->st_blocks);
timebuf[0] = 0;
if (ctime_r(&sb->st_atime, timebuf, 512)) {
(void) printf("st_atime\t\t");
(void) printf("%s", timebuf);
}
timebuf[0] = 0;
if (ctime_r(&sb->st_mtime, timebuf, 512)) {
(void) printf("st_mtime\t\t");
(void) printf("%s", timebuf);
}
timebuf[0] = 0;
if (ctime_r(&sb->st_ctime, timebuf, 512)) {
(void) printf("st_ctime\t\t");
(void) printf("%s", timebuf);
}
}
static void
print_xvs(uint64_t xvs)
{
uint_t bits;
int idx = 0;
if (xvs == 0)
return;
(void) printf("-------------------\n");
(void) printf("Attribute bit(s) set:\n");
(void) printf("-------------------\n");
bits = xvs & ((1 << F_ATTR_ALL) - 1);
while (bits) {
uint_t rest = bits >> 1;
if (bits & 1) {
(void) printf("%s", attr_to_name((f_attr_t)idx));
if (rest)
(void) printf(", ");
}
idx++;
bits = rest;
}
(void) printf("\n");
}
int
main(int argc, char **argv)
{
zut_lookup_t lk = {0};
zut_readdir_t rd = {0};
boolean_t checking = B_FALSE;
boolean_t looking = B_FALSE;
boolean_t reading = B_FALSE;
boolean_t bflag = B_FALSE;
long rddir_bufsize = BIGBUF;
int error = 0;
int check;
int fd;
int c;
while ((c = getopt(argc, argv, "lisaerb:ASE")) != -1) {
switch (c) {
case 'l':
looking = B_TRUE;
break;
case 'i':
lk.zl_reqflags |= ZUT_IGNORECASE;
looking = B_TRUE;
break;
case 's':
lk.zl_reqflags |= ZUT_GETSTAT;
looking = B_TRUE;
break;
case 'a':
rd.zr_reqflags |= ZUT_ACCFILTER;
reading = B_TRUE;
break;
case 'e':
rd.zr_reqflags |= ZUT_EXTRDDIR;
reading = B_TRUE;
break;
case 'r':
reading = B_TRUE;
break;
case 'b':
reading = B_TRUE;
bflag = B_TRUE;
rddir_bufsize = strtol(optarg, NULL, 0);
break;
case 'A':
checking = B_TRUE;
check = _PC_ACCESS_FILTERING;
break;
case 'S':
checking = B_TRUE;
check = _PC_SATTR_ENABLED;
break;
case 'E':
checking = B_TRUE;
check = _PC_SATTR_EXISTS;
break;
case '?':
default:
usage(argv[0]); /* no return */
}
}
if ((checking && looking) || (checking && reading) ||
(looking && reading) || (!reading && bflag) ||
(!checking && !reading && !looking))
usage(argv[0]); /* no return */
if (rddir_bufsize < LILBUF || rddir_bufsize > MAXBUF) {
(void) fprintf(stderr, "Sorry, buffer size "
"must be >= %d and less than or equal to %d bytes.\n",
(int)LILBUF, MAXBUF);
exit(EINVAL);
}
if (checking) {
char pathbuf[MAXPATHLEN];
long result;
if (argc - optind < 1)
usage(argv[0]); /* no return */
(void) strlcpy(pathbuf, argv[optind], MAXPATHLEN);
result = pathconf(pathbuf, check);
(void) printf("pathconf(2) check for %s\n", pathbuf);
switch (check) {
case _PC_SATTR_ENABLED:
(void) printf("System attributes ");
if (result != 0)
(void) printf("Enabled\n");
else
(void) printf("Not enabled\n");
break;
case _PC_SATTR_EXISTS:
(void) printf("System attributes ");
if (result != 0)
(void) printf("Exist\n");
else
(void) printf("Do not exist\n");
break;
case _PC_ACCESS_FILTERING:
(void) printf("Access filtering ");
if (result != 0)
(void) printf("Available\n");
else
(void) printf("Not available\n");
break;
}
return (result);
}
if ((fd = open(ZUT_DEV, O_RDONLY)) < 0) {
perror(ZUT_DEV);
return (ENXIO);
}
if (reading) {
char *buf;
if (argc - optind < 1)
usage(argv[0]); /* no return */
(void) strlcpy(rd.zr_dir, argv[optind], MAXPATHLEN);
if (argc - optind > 1) {
(void) strlcpy(rd.zr_file, argv[optind + 1],
MAXNAMELEN);
rd.zr_reqflags |= ZUT_XATTR;
}
if ((buf = malloc(rddir_bufsize)) == NULL) {
error = errno;
perror("malloc");
(void) close(fd);
return (error);
}
rd.zr_buf = (uint64_t)(uintptr_t)buf;
rd.zr_buflen = rddir_bufsize;
while (!rd.zr_eof) {
int ierr;
if ((ierr = ioctl(fd, ZUT_IOC_READDIR, &rd)) != 0) {
(void) fprintf(stderr,
"IOCTL error: %s (%d)\n",
strerror(ierr), ierr);
free(buf);
(void) close(fd);
return (ierr);
}
if (rd.zr_retcode) {
(void) fprintf(stderr,
"readdir result: %s (%d)\n",
strerror(rd.zr_retcode), rd.zr_retcode);
free(buf);
(void) close(fd);
return (rd.zr_retcode);
}
if (rd.zr_reqflags & ZUT_EXTRDDIR)
print_extd_entries(&rd);
else
print_entries(&rd);
}
free(buf);
} else {
int ierr;
if (argc - optind < 2)
usage(argv[0]); /* no return */
(void) strlcpy(lk.zl_dir, argv[optind], MAXPATHLEN);
(void) strlcpy(lk.zl_file, argv[optind + 1], MAXNAMELEN);
if (argc - optind > 2) {
(void) strlcpy(lk.zl_xfile,
argv[optind + 2], MAXNAMELEN);
lk.zl_reqflags |= ZUT_XATTR;
}
if ((ierr = ioctl(fd, ZUT_IOC_LOOKUP, &lk)) != 0) {
(void) fprintf(stderr,
"IOCTL error: %s (%d)\n",
strerror(ierr), ierr);
(void) close(fd);
return (ierr);
}
(void) printf("\nLookup of ");
if (lk.zl_reqflags & ZUT_XATTR) {
(void) printf("extended attribute \"%s\" of ",
lk.zl_xfile);
}
(void) printf("file \"%s\" ", lk.zl_file);
(void) printf("in directory \"%s\" ", lk.zl_dir);
if (lk.zl_retcode) {
(void) printf("failed: %s (%d)\n",
strerror(lk.zl_retcode), lk.zl_retcode);
(void) close(fd);
return (lk.zl_retcode);
}
(void) printf("succeeded.\n");
if (lk.zl_reqflags & ZUT_IGNORECASE) {
(void) printf("----------------------------\n");
(void) printf("dirent flags: 0x%0x\n", lk.zl_deflags);
(void) printf("real name: %s\n", lk.zl_real);
}
if (lk.zl_reqflags & ZUT_GETSTAT) {
(void) printf("----------------------------\n");
print_stats(&lk.zl_statbuf);
print_xvs(lk.zl_xvattrs);
}
}
(void) close(fd);
return (0);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <errno.h>
#include <libgen.h>
#include <libintl.h>
@ -50,22 +48,6 @@ safe_malloc(size_t size)
return (data);
}
/*
* Same as above, but for strdup()
*/
char *
safe_strdup(const char *str)
{
char *ret;
if ((ret = strdup(str)) == NULL) {
(void) fprintf(stderr, "internal error: out of memory\n");
exit(1);
}
return (ret);
}
/*
* Display an out of memory error message and abort the current program.
*/

View File

@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef ZPOOL_UTIL_H
@ -37,7 +36,6 @@ extern "C" {
* Basic utility functions
*/
void *safe_malloc(size_t);
char *safe_strdup(const char *);
void zpool_no_memory(void);
uint_t num_logs(nvlist_t *nv);
@ -46,7 +44,9 @@ uint_t num_logs(nvlist_t *nv);
*/
nvlist_t *make_root_vdev(zpool_handle_t *zhp, int force, int check_rep,
boolean_t isreplace, boolean_t dryrun, int argc, char **argv);
boolean_t replacing, boolean_t dryrun, int argc, char **argv);
nvlist_t *split_mirror_vdev(zpool_handle_t *zhp, char *newname,
nvlist_t *props, splitflags_t flags, int argc, char **argv);
/*
* Pool list functions

View File

@ -20,8 +20,7 @@
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@ -66,6 +65,7 @@
#include <fcntl.h>
#include <libintl.h>
#include <libnvpair.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
@ -77,6 +77,10 @@
#include "zpool_util.h"
#define DISK_ROOT "/dev/dsk"
#define RDISK_ROOT "/dev/rdsk"
#define BACKUP_SLICE "s2"
/*
* For any given vdev specification, we can have multiple errors. The
* vdev_error() function keeps track of whether we have seen an error yet, and
@ -107,6 +111,170 @@ vdev_error(const char *fmt, ...)
va_end(ap);
}
#ifdef sun
static void
libdiskmgt_error(int error)
{
/*
* ENXIO/ENODEV is a valid error message if the device doesn't live in
* /dev/dsk. Don't bother printing an error message in this case.
*/
if (error == ENXIO || error == ENODEV)
return;
(void) fprintf(stderr, gettext("warning: device in use checking "
"failed: %s\n"), strerror(error));
}
/*
* Validate a device, passing the bulk of the work off to libdiskmgt.
*/
static int
check_slice(const char *path, int force, boolean_t wholedisk, boolean_t isspare)
{
char *msg;
int error = 0;
dm_who_type_t who;
if (force)
who = DM_WHO_ZPOOL_FORCE;
else if (isspare)
who = DM_WHO_ZPOOL_SPARE;
else
who = DM_WHO_ZPOOL;
if (dm_inuse((char *)path, &msg, who, &error) || error) {
if (error != 0) {
libdiskmgt_error(error);
return (0);
} else {
vdev_error("%s", msg);
free(msg);
return (-1);
}
}
/*
* If we're given a whole disk, ignore overlapping slices since we're
* about to label it anyway.
*/
error = 0;
if (!wholedisk && !force &&
(dm_isoverlapping((char *)path, &msg, &error) || error)) {
if (error == 0) {
/* dm_isoverlapping returned -1 */
vdev_error(gettext("%s overlaps with %s\n"), path, msg);
free(msg);
return (-1);
} else if (error != ENODEV) {
/* libdiskmgt's devcache only handles physical drives */
libdiskmgt_error(error);
return (0);
}
}
return (0);
}
/*
* Validate a whole disk. Iterate over all slices on the disk and make sure
* that none is in use by calling check_slice().
*/
static int
check_disk(const char *name, dm_descriptor_t disk, int force, int isspare)
{
dm_descriptor_t *drive, *media, *slice;
int err = 0;
int i;
int ret;
/*
* Get the drive associated with this disk. This should never fail,
* because we already have an alias handle open for the device.
*/
if ((drive = dm_get_associated_descriptors(disk, DM_DRIVE,
&err)) == NULL || *drive == NULL) {
if (err)
libdiskmgt_error(err);
return (0);
}
if ((media = dm_get_associated_descriptors(*drive, DM_MEDIA,
&err)) == NULL) {
dm_free_descriptors(drive);
if (err)
libdiskmgt_error(err);
return (0);
}
dm_free_descriptors(drive);
/*
* It is possible that the user has specified a removable media drive,
* and the media is not present.
*/
if (*media == NULL) {
dm_free_descriptors(media);
vdev_error(gettext("'%s' has no media in drive\n"), name);
return (-1);
}
if ((slice = dm_get_associated_descriptors(*media, DM_SLICE,
&err)) == NULL) {
dm_free_descriptors(media);
if (err)
libdiskmgt_error(err);
return (0);
}
dm_free_descriptors(media);
ret = 0;
/*
* Iterate over all slices and report any errors. We don't care about
* overlapping slices because we are using the whole disk.
*/
for (i = 0; slice[i] != NULL; i++) {
char *name = dm_get_name(slice[i], &err);
if (check_slice(name, force, B_TRUE, isspare) != 0)
ret = -1;
dm_free_name(name);
}
dm_free_descriptors(slice);
return (ret);
}
/*
* Validate a device.
*/
static int
check_device(const char *path, boolean_t force, boolean_t isspare)
{
dm_descriptor_t desc;
int err;
char *dev;
/*
* For whole disks, libdiskmgt does not include the leading dev path.
*/
dev = strrchr(path, '/');
assert(dev != NULL);
dev++;
if ((desc = dm_get_descriptor_by_name(DM_ALIAS, dev, &err)) != NULL) {
err = check_disk(path, desc, force, isspare);
dm_free_descriptor(desc);
return (err);
}
return (check_slice(path, force, B_FALSE, isspare));
}
#endif /* sun */
/*
* Check that a file is valid. All we can do in this case is check that it's
* not in use by another pool, and not in use by swap.
@ -121,7 +289,7 @@ check_file(const char *file, boolean_t force, boolean_t isspare)
pool_state_t state;
boolean_t inuse;
#if 0
#ifdef sun
if (dm_inuse_swap(file, &err)) {
if (err)
libdiskmgt_error(err);
@ -185,7 +353,7 @@ check_file(const char *file, boolean_t force, boolean_t isspare)
}
static int
check_provider(const char *name, boolean_t force, boolean_t isspare)
check_device(const char *name, boolean_t force, boolean_t isspare)
{
char path[MAXPATHLEN];
@ -206,24 +374,44 @@ check_provider(const char *name, boolean_t force, boolean_t isspare)
* it isn't.
*/
static boolean_t
is_whole_disk(const char *name)
is_whole_disk(const char *arg)
{
#ifdef sun
struct dk_gpt *label;
int fd;
char path[MAXPATHLEN];
(void) snprintf(path, sizeof (path), "%s%s%s",
RDISK_ROOT, strrchr(arg, '/'), BACKUP_SLICE);
if ((fd = open(path, O_RDWR | O_NDELAY)) < 0)
return (B_FALSE);
if (efi_alloc_and_init(fd, EFI_NUMPAR, &label) != 0) {
(void) close(fd);
return (B_FALSE);
}
efi_free(label);
(void) close(fd);
return (B_TRUE);
#else
int fd;
fd = g_open(name, 0);
fd = g_open(arg, 0);
if (fd >= 0) {
g_close(fd);
return (B_TRUE);
}
return (B_FALSE);
#endif
}
/*
* Create a leaf vdev. Determine if this is a GEOM provider.
* Valid forms for a leaf vdev are:
* Create a leaf vdev. Determine if this is a file or a device. If it's a
* device, fill in the device id to make a complete nvlist. Valid forms for a
* leaf vdev are:
*
* /dev/xxx Complete path to a GEOM provider
* xxx Shorthand for /dev/xxx
* /dev/dsk/xxx Complete disk path
* /xxx Full path to file
* xxx Shorthand for /dev/dsk/xxx
*/
static nvlist_t *
make_leaf_vdev(const char *arg, uint64_t is_log)
@ -290,10 +478,18 @@ make_leaf_vdev(const char *arg, uint64_t is_log)
}
}
#ifdef __FreeBSD__
if (S_ISCHR(statbuf.st_mode)) {
statbuf.st_mode &= ~S_IFCHR;
statbuf.st_mode |= S_IFBLK;
wholedisk = B_FALSE;
}
#endif
/*
* Determine whether this is a device or a file.
*/
if (wholedisk) {
if (wholedisk || S_ISBLK(statbuf.st_mode)) {
type = VDEV_TYPE_DISK;
} else if (S_ISREG(statbuf.st_mode)) {
type = VDEV_TYPE_FILE;
@ -314,12 +510,12 @@ make_leaf_vdev(const char *arg, uint64_t is_log)
verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_IS_LOG, is_log) == 0);
if (strcmp(type, VDEV_TYPE_DISK) == 0)
verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK,
(uint64_t)B_FALSE) == 0);
(uint64_t)wholedisk) == 0);
/*
* For a whole disk, defer getting its devid until after labeling it.
*/
if (1 || (S_ISBLK(statbuf.st_mode) && !wholedisk)) {
if (S_ISBLK(statbuf.st_mode) && !wholedisk) {
/*
* Get the devid for the device.
*/
@ -527,16 +723,14 @@ get_replication(nvlist_t *nvroot, boolean_t fatal)
*/
if ((fd = open(path, O_RDONLY)) >= 0) {
err = fstat64(fd, &statbuf);
if (err == 0 &&
S_ISCHR(statbuf.st_mode)) {
err = ioctl(fd, DIOCGMEDIASIZE,
&statbuf.st_size);
}
(void) close(fd);
} else {
err = stat64(path, &statbuf);
}
if (err != 0 || statbuf.st_size == 0)
if (err != 0 ||
statbuf.st_size == 0 ||
statbuf.st_size == MAXOFFSET_T)
continue;
size = statbuf.st_size;
@ -714,6 +908,112 @@ check_replication(nvlist_t *config, nvlist_t *newroot)
return (ret);
}
#ifdef sun
/*
* Go through and find any whole disks in the vdev specification, labelling them
* as appropriate. When constructing the vdev spec, we were unable to open this
* device in order to provide a devid. Now that we have labelled the disk and
* know that slice 0 is valid, we can construct the devid now.
*
* If the disk was already labeled with an EFI label, we will have gotten the
* devid already (because we were able to open the whole disk). Otherwise, we
* need to get the devid after we label the disk.
*/
static int
make_disks(zpool_handle_t *zhp, nvlist_t *nv)
{
nvlist_t **child;
uint_t c, children;
char *type, *path, *diskname;
char buf[MAXPATHLEN];
uint64_t wholedisk;
int fd;
int ret;
ddi_devid_t devid;
char *minor = NULL, *devid_str = NULL;
verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
&child, &children) != 0) {
if (strcmp(type, VDEV_TYPE_DISK) != 0)
return (0);
/*
* We have a disk device. Get the path to the device
* and see if it's a whole disk by appending the backup
* slice and stat()ing the device.
*/
verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
&wholedisk) != 0 || !wholedisk)
return (0);
diskname = strrchr(path, '/');
assert(diskname != NULL);
diskname++;
if (zpool_label_disk(g_zfs, zhp, diskname) == -1)
return (-1);
/*
* Fill in the devid, now that we've labeled the disk.
*/
(void) snprintf(buf, sizeof (buf), "%ss0", path);
if ((fd = open(buf, O_RDONLY)) < 0) {
(void) fprintf(stderr,
gettext("cannot open '%s': %s\n"),
buf, strerror(errno));
return (-1);
}
if (devid_get(fd, &devid) == 0) {
if (devid_get_minor_name(fd, &minor) == 0 &&
(devid_str = devid_str_encode(devid, minor)) !=
NULL) {
verify(nvlist_add_string(nv,
ZPOOL_CONFIG_DEVID, devid_str) == 0);
}
if (devid_str != NULL)
devid_str_free(devid_str);
if (minor != NULL)
devid_str_free(minor);
devid_free(devid);
}
/*
* Update the path to refer to the 's0' slice. The presence of
* the 'whole_disk' field indicates to the CLI that we should
* chop off the slice number when displaying the device in
* future output.
*/
verify(nvlist_add_string(nv, ZPOOL_CONFIG_PATH, buf) == 0);
(void) close(fd);
return (0);
}
for (c = 0; c < children; c++)
if ((ret = make_disks(zhp, child[c])) != 0)
return (ret);
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
&child, &children) == 0)
for (c = 0; c < children; c++)
if ((ret = make_disks(zhp, child[c])) != 0)
return (ret);
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
&child, &children) == 0)
for (c = 0; c < children; c++)
if ((ret = make_disks(zhp, child[c])) != 0)
return (ret);
return (0);
}
#endif /* sun */
/*
* Determine if the given path is a hot spare within the given configuration.
*/
@ -742,8 +1042,8 @@ is_spare(nvlist_t *config, const char *path)
return (B_FALSE);
}
free(name);
(void) close(fd);
verify(nvlist_lookup_uint64(label, ZPOOL_CONFIG_GUID, &guid) == 0);
nvlist_free(label);
@ -767,8 +1067,8 @@ is_spare(nvlist_t *config, const char *path)
* the majority of this task.
*/
static int
check_in_use(nvlist_t *config, nvlist_t *nv, int force, int isreplacing,
int isspare)
check_in_use(nvlist_t *config, nvlist_t *nv, boolean_t force,
boolean_t replacing, boolean_t isspare)
{
nvlist_t **child;
uint_t c, children;
@ -789,14 +1089,22 @@ check_in_use(nvlist_t *config, nvlist_t *nv, int force, int isreplacing,
* hot spare within the same pool. If so, we allow it
* regardless of what libdiskmgt or zpool_in_use() says.
*/
if (isreplacing) {
(void) strlcpy(buf, path, sizeof (buf));
if (replacing) {
#ifdef sun
if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
&wholedisk) == 0 && wholedisk)
(void) snprintf(buf, sizeof (buf), "%ss0",
path);
else
#endif
(void) strlcpy(buf, path, sizeof (buf));
if (is_spare(config, buf))
return (0);
}
if (strcmp(type, VDEV_TYPE_DISK) == 0)
ret = check_provider(path, force, isspare);
ret = check_device(path, force, isspare);
if (strcmp(type, VDEV_TYPE_FILE) == 0)
ret = check_file(path, force, isspare);
@ -806,40 +1114,55 @@ check_in_use(nvlist_t *config, nvlist_t *nv, int force, int isreplacing,
for (c = 0; c < children; c++)
if ((ret = check_in_use(config, child[c], force,
isreplacing, B_FALSE)) != 0)
replacing, B_FALSE)) != 0)
return (ret);
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
&child, &children) == 0)
for (c = 0; c < children; c++)
if ((ret = check_in_use(config, child[c], force,
isreplacing, B_TRUE)) != 0)
replacing, B_TRUE)) != 0)
return (ret);
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
&child, &children) == 0)
for (c = 0; c < children; c++)
if ((ret = check_in_use(config, child[c], force,
isreplacing, B_FALSE)) != 0)
replacing, B_FALSE)) != 0)
return (ret);
return (0);
}
static const char *
is_grouping(const char *type, int *mindev)
is_grouping(const char *type, int *mindev, int *maxdev)
{
if (strcmp(type, "raidz") == 0 || strcmp(type, "raidz1") == 0) {
if (strncmp(type, "raidz", 5) == 0) {
const char *p = type + 5;
char *end;
long nparity;
if (*p == '\0') {
nparity = 1;
} else if (*p == '0') {
return (NULL); /* no zero prefixes allowed */
} else {
errno = 0;
nparity = strtol(p, &end, 10);
if (errno != 0 || nparity < 1 || nparity >= 255 ||
*end != '\0')
return (NULL);
}
if (mindev != NULL)
*mindev = 2;
*mindev = nparity + 1;
if (maxdev != NULL)
*maxdev = 255;
return (VDEV_TYPE_RAIDZ);
}
if (strcmp(type, "raidz2") == 0) {
if (mindev != NULL)
*mindev = 3;
return (VDEV_TYPE_RAIDZ);
}
if (maxdev != NULL)
*maxdev = INT_MAX;
if (strcmp(type, "mirror") == 0) {
if (mindev != NULL)
@ -878,7 +1201,7 @@ nvlist_t *
construct_spec(int argc, char **argv)
{
nvlist_t *nvroot, *nv, **top, **spares, **l2cache;
int t, toplevels, mindev, nspares, nlogs, nl2cache;
int t, toplevels, mindev, maxdev, nspares, nlogs, nl2cache;
const char *type;
uint64_t is_log;
boolean_t seen_logs;
@ -900,7 +1223,7 @@ construct_spec(int argc, char **argv)
* If it's a mirror or raidz, the subsequent arguments are
* its leaves -- until we encounter the next mirror or raidz.
*/
if ((type = is_grouping(argv[0], &mindev)) != NULL) {
if ((type = is_grouping(argv[0], &mindev, &maxdev)) != NULL) {
nvlist_t **child = NULL;
int c, children = 0;
@ -957,7 +1280,7 @@ construct_spec(int argc, char **argv)
}
for (c = 1; c < argc; c++) {
if (is_grouping(argv[c], NULL) != NULL)
if (is_grouping(argv[c], NULL, NULL) != NULL)
break;
children++;
child = realloc(child,
@ -977,6 +1300,13 @@ construct_spec(int argc, char **argv)
return (NULL);
}
if (children > maxdev) {
(void) fprintf(stderr, gettext("invalid vdev "
"specification: %s supports no more than "
"%d devices\n"), argv[0], maxdev);
return (NULL);
}
argc -= c;
argv += c;
@ -1071,6 +1401,54 @@ construct_spec(int argc, char **argv)
return (nvroot);
}
nvlist_t *
split_mirror_vdev(zpool_handle_t *zhp, char *newname, nvlist_t *props,
splitflags_t flags, int argc, char **argv)
{
nvlist_t *newroot = NULL, **child;
uint_t c, children;
if (argc > 0) {
if ((newroot = construct_spec(argc, argv)) == NULL) {
(void) fprintf(stderr, gettext("Unable to build a "
"pool from the specified devices\n"));
return (NULL);
}
#ifdef sun
if (!flags.dryrun && make_disks(zhp, newroot) != 0) {
nvlist_free(newroot);
return (NULL);
}
#endif
/* avoid any tricks in the spec */
verify(nvlist_lookup_nvlist_array(newroot,
ZPOOL_CONFIG_CHILDREN, &child, &children) == 0);
for (c = 0; c < children; c++) {
char *path;
const char *type;
int min, max;
verify(nvlist_lookup_string(child[c],
ZPOOL_CONFIG_PATH, &path) == 0);
if ((type = is_grouping(path, &min, &max)) != NULL) {
(void) fprintf(stderr, gettext("Cannot use "
"'%s' as a device for splitting\n"), type);
nvlist_free(newroot);
return (NULL);
}
}
}
if (zpool_vdev_split(zhp, newname, &newroot, props, flags) != 0) {
if (newroot != NULL)
nvlist_free(newroot);
return (NULL);
}
return (newroot);
}
/*
* Get and validate the contents of the given vdev specification. This ensures
@ -1084,7 +1462,7 @@ construct_spec(int argc, char **argv)
*/
nvlist_t *
make_root_vdev(zpool_handle_t *zhp, int force, int check_rep,
boolean_t isreplacing, boolean_t dryrun, int argc, char **argv)
boolean_t replacing, boolean_t dryrun, int argc, char **argv)
{
nvlist_t *newroot;
nvlist_t *poolconfig = NULL;
@ -1107,8 +1485,7 @@ make_root_vdev(zpool_handle_t *zhp, int force, int check_rep,
* uses (such as a dedicated dump device) that even '-f' cannot
* override.
*/
if (check_in_use(poolconfig, newroot, force, isreplacing,
B_FALSE) != 0) {
if (check_in_use(poolconfig, newroot, force, replacing, B_FALSE) != 0) {
nvlist_free(newroot);
return (NULL);
}
@ -1123,5 +1500,15 @@ make_root_vdev(zpool_handle_t *zhp, int force, int check_rep,
return (NULL);
}
#ifdef sun
/*
* Run through the vdev specification and label any whole disks found.
*/
if (!dryrun && make_disks(zhp, newroot) != 0) {
nvlist_free(newroot);
return (NULL);
}
#endif
return (newroot);
}

View File

@ -0,0 +1,67 @@
'\" te
.\" Copyright (c) 2009, 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 zstreamdump 1M "21 Sep 2009" "SunOS 5.11" "System Administration Commands"
.SH NAME
zstreamdump \- filter data in zfs send stream
.SH SYNOPSIS
.LP
.nf
\fBzstreamdump\fR [\fB-C\fR] [\fB-v\fR]
.fi
.SH DESCRIPTION
.sp
.LP
The \fBzstreamdump\fR utility reads from the output of the \fBzfs send\fR command, then displays headers and some statistics from that output. See \fBzfs\fR(1M).
.SH OPTIONS
.sp
.LP
The following options are supported:
.sp
.ne 2
.mk
.na
\fB\fB-C\fR\fR
.ad
.sp .6
.RS 4n
Suppress the validation of checksums.
.RE
.sp
.ne 2
.mk
.na
\fB\fB-v\fR\fR
.ad
.sp .6
.RS 4n
Verbose. Dump all headers, not only begin and end headers.
.RE
.SH ATTRIBUTES
.sp
.LP
See \fBattributes\fR(5) for descriptions of the following attributes:
.sp
.sp
.TS
tab() box;
cw(2.75i) |cw(2.75i)
lw(2.75i) |lw(2.75i)
.
ATTRIBUTE TYPEATTRIBUTE VALUE
_
AvailabilitySUNWzfsu
_
Interface StabilityUncommitted
.TE
.SH SEE ALSO
.sp
.LP
\fBzfs\fR(1M), \fBattributes\fR(5)

View File

@ -0,0 +1,429 @@
/*
* CDDL HEADER START
*
* 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]
*
* CDDL HEADER END
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <libnvpair.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <sys/dmu.h>
#include <sys/zfs_ioctl.h>
#include <zfs_fletcher.h>
uint64_t drr_record_count[DRR_NUMTYPES];
uint64_t total_write_size = 0;
uint64_t total_stream_len = 0;
FILE *send_stream = 0;
boolean_t do_byteswap = B_FALSE;
boolean_t do_cksum = B_TRUE;
#define INITIAL_BUFLEN (1<<20)
static void
usage(void)
{
(void) fprintf(stderr, "usage: zstreamdump [-v] [-C] < file\n");
(void) fprintf(stderr, "\t -v -- verbose\n");
(void) fprintf(stderr, "\t -C -- suppress checksum verification\n");
exit(1);
}
/*
* ssread - send stream read.
*
* Read while computing incremental checksum
*/
static size_t
ssread(void *buf, size_t len, zio_cksum_t *cksum)
{
size_t outlen;
if ((outlen = fread(buf, len, 1, send_stream)) == 0)
return (0);
if (do_cksum && cksum) {
if (do_byteswap)
fletcher_4_incremental_byteswap(buf, len, cksum);
else
fletcher_4_incremental_native(buf, len, cksum);
}
total_stream_len += len;
return (outlen);
}
int
main(int argc, char *argv[])
{
char *buf = malloc(INITIAL_BUFLEN);
dmu_replay_record_t thedrr;
dmu_replay_record_t *drr = &thedrr;
struct drr_begin *drrb = &thedrr.drr_u.drr_begin;
struct drr_end *drre = &thedrr.drr_u.drr_end;
struct drr_object *drro = &thedrr.drr_u.drr_object;
struct drr_freeobjects *drrfo = &thedrr.drr_u.drr_freeobjects;
struct drr_write *drrw = &thedrr.drr_u.drr_write;
struct drr_write_byref *drrwbr = &thedrr.drr_u.drr_write_byref;
struct drr_free *drrf = &thedrr.drr_u.drr_free;
struct drr_spill *drrs = &thedrr.drr_u.drr_spill;
char c;
boolean_t verbose = B_FALSE;
boolean_t first = B_TRUE;
int err;
zio_cksum_t zc = { 0 };
zio_cksum_t pcksum = { 0 };
while ((c = getopt(argc, argv, ":vC")) != -1) {
switch (c) {
case 'C':
do_cksum = B_FALSE;
break;
case 'v':
verbose = B_TRUE;
break;
case ':':
(void) fprintf(stderr,
"missing argument for '%c' option\n", optopt);
usage();
break;
case '?':
(void) fprintf(stderr, "invalid option '%c'\n",
optopt);
usage();
}
}
if (isatty(STDIN_FILENO)) {
(void) fprintf(stderr,
"Error: Backup stream can not be read "
"from a terminal.\n"
"You must redirect standard input.\n");
exit(1);
}
send_stream = stdin;
pcksum = zc;
while (ssread(drr, sizeof (dmu_replay_record_t), &zc)) {
if (first) {
if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {
do_byteswap = B_TRUE;
if (do_cksum) {
ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0);
/*
* recalculate header checksum now
* that we know it needs to be
* byteswapped.
*/
fletcher_4_incremental_byteswap(drr,
sizeof (dmu_replay_record_t), &zc);
}
} else if (drrb->drr_magic != DMU_BACKUP_MAGIC) {
(void) fprintf(stderr, "Invalid stream "
"(bad magic number)\n");
exit(1);
}
first = B_FALSE;
}
if (do_byteswap) {
drr->drr_type = BSWAP_32(drr->drr_type);
drr->drr_payloadlen =
BSWAP_32(drr->drr_payloadlen);
}
/*
* At this point, the leading fields of the replay record
* (drr_type and drr_payloadlen) have been byte-swapped if
* necessary, but the rest of the data structure (the
* union of type-specific structures) is still in its
* original state.
*/
if (drr->drr_type >= DRR_NUMTYPES) {
(void) printf("INVALID record found: type 0x%x\n",
drr->drr_type);
(void) printf("Aborting.\n");
exit(1);
}
drr_record_count[drr->drr_type]++;
switch (drr->drr_type) {
case DRR_BEGIN:
if (do_byteswap) {
drrb->drr_magic = BSWAP_64(drrb->drr_magic);
drrb->drr_versioninfo =
BSWAP_64(drrb->drr_versioninfo);
drrb->drr_creation_time =
BSWAP_64(drrb->drr_creation_time);
drrb->drr_type = BSWAP_32(drrb->drr_type);
drrb->drr_flags = BSWAP_32(drrb->drr_flags);
drrb->drr_toguid = BSWAP_64(drrb->drr_toguid);
drrb->drr_fromguid =
BSWAP_64(drrb->drr_fromguid);
}
(void) printf("BEGIN record\n");
(void) printf("\thdrtype = %lld\n",
DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo));
(void) printf("\tfeatures = %llx\n",
DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo));
(void) printf("\tmagic = %llx\n",
(u_longlong_t)drrb->drr_magic);
(void) printf("\tcreation_time = %llx\n",
(u_longlong_t)drrb->drr_creation_time);
(void) printf("\ttype = %u\n", drrb->drr_type);
(void) printf("\tflags = 0x%x\n", drrb->drr_flags);
(void) printf("\ttoguid = %llx\n",
(u_longlong_t)drrb->drr_toguid);
(void) printf("\tfromguid = %llx\n",
(u_longlong_t)drrb->drr_fromguid);
(void) printf("\ttoname = %s\n", drrb->drr_toname);
if (verbose)
(void) printf("\n");
if ((DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
DMU_COMPOUNDSTREAM) && drr->drr_payloadlen != 0) {
nvlist_t *nv;
int sz = drr->drr_payloadlen;
if (sz > 1<<20) {
free(buf);
buf = malloc(sz);
}
(void) ssread(buf, sz, &zc);
if (ferror(send_stream))
perror("fread");
err = nvlist_unpack(buf, sz, &nv, 0);
if (err)
perror(strerror(err));
nvlist_print(stdout, nv);
nvlist_free(nv);
}
break;
case DRR_END:
if (do_byteswap) {
drre->drr_checksum.zc_word[0] =
BSWAP_64(drre->drr_checksum.zc_word[0]);
drre->drr_checksum.zc_word[1] =
BSWAP_64(drre->drr_checksum.zc_word[1]);
drre->drr_checksum.zc_word[2] =
BSWAP_64(drre->drr_checksum.zc_word[2]);
drre->drr_checksum.zc_word[3] =
BSWAP_64(drre->drr_checksum.zc_word[3]);
}
/*
* We compare against the *previous* checksum
* value, because the stored checksum is of
* everything before the DRR_END record.
*/
if (do_cksum && !ZIO_CHECKSUM_EQUAL(drre->drr_checksum,
pcksum)) {
(void) printf("Expected checksum differs from "
"checksum in stream.\n");
(void) printf("Expected checksum = "
"%llx/%llx/%llx/%llx\n",
pcksum.zc_word[0],
pcksum.zc_word[1],
pcksum.zc_word[2],
pcksum.zc_word[3]);
}
(void) printf("END checksum = %llx/%llx/%llx/%llx\n",
drre->drr_checksum.zc_word[0],
drre->drr_checksum.zc_word[1],
drre->drr_checksum.zc_word[2],
drre->drr_checksum.zc_word[3]);
ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0);
break;
case DRR_OBJECT:
if (do_byteswap) {
drro->drr_object = BSWAP_64(drro->drr_object);
drro->drr_type = BSWAP_32(drro->drr_type);
drro->drr_bonustype =
BSWAP_32(drro->drr_bonustype);
drro->drr_blksz = BSWAP_32(drro->drr_blksz);
drro->drr_bonuslen =
BSWAP_32(drro->drr_bonuslen);
drro->drr_toguid = BSWAP_64(drro->drr_toguid);
}
if (verbose) {
(void) printf("OBJECT object = %llu type = %u "
"bonustype = %u blksz = %u bonuslen = %u\n",
(u_longlong_t)drro->drr_object,
drro->drr_type,
drro->drr_bonustype,
drro->drr_blksz,
drro->drr_bonuslen);
}
if (drro->drr_bonuslen > 0) {
(void) ssread(buf, P2ROUNDUP(drro->drr_bonuslen,
8), &zc);
}
break;
case DRR_FREEOBJECTS:
if (do_byteswap) {
drrfo->drr_firstobj =
BSWAP_64(drrfo->drr_firstobj);
drrfo->drr_numobjs =
BSWAP_64(drrfo->drr_numobjs);
drrfo->drr_toguid = BSWAP_64(drrfo->drr_toguid);
}
if (verbose) {
(void) printf("FREEOBJECTS firstobj = %llu "
"numobjs = %llu\n",
(u_longlong_t)drrfo->drr_firstobj,
(u_longlong_t)drrfo->drr_numobjs);
}
break;
case DRR_WRITE:
if (do_byteswap) {
drrw->drr_object = BSWAP_64(drrw->drr_object);
drrw->drr_type = BSWAP_32(drrw->drr_type);
drrw->drr_offset = BSWAP_64(drrw->drr_offset);
drrw->drr_length = BSWAP_64(drrw->drr_length);
drrw->drr_toguid = BSWAP_64(drrw->drr_toguid);
drrw->drr_key.ddk_prop =
BSWAP_64(drrw->drr_key.ddk_prop);
}
if (verbose) {
(void) printf("WRITE object = %llu type = %u "
"checksum type = %u\n"
"offset = %llu length = %llu "
"props = %llx\n",
(u_longlong_t)drrw->drr_object,
drrw->drr_type,
drrw->drr_checksumtype,
(u_longlong_t)drrw->drr_offset,
(u_longlong_t)drrw->drr_length,
(u_longlong_t)drrw->drr_key.ddk_prop);
}
(void) ssread(buf, drrw->drr_length, &zc);
total_write_size += drrw->drr_length;
break;
case DRR_WRITE_BYREF:
if (do_byteswap) {
drrwbr->drr_object =
BSWAP_64(drrwbr->drr_object);
drrwbr->drr_offset =
BSWAP_64(drrwbr->drr_offset);
drrwbr->drr_length =
BSWAP_64(drrwbr->drr_length);
drrwbr->drr_toguid =
BSWAP_64(drrwbr->drr_toguid);
drrwbr->drr_refguid =
BSWAP_64(drrwbr->drr_refguid);
drrwbr->drr_refobject =
BSWAP_64(drrwbr->drr_refobject);
drrwbr->drr_refoffset =
BSWAP_64(drrwbr->drr_refoffset);
drrwbr->drr_key.ddk_prop =
BSWAP_64(drrwbr->drr_key.ddk_prop);
}
if (verbose) {
(void) printf("WRITE_BYREF object = %llu "
"checksum type = %u props = %llx\n"
"offset = %llu length = %llu\n"
"toguid = %llx refguid = %llx\n"
"refobject = %llu refoffset = %llu\n",
(u_longlong_t)drrwbr->drr_object,
drrwbr->drr_checksumtype,
(u_longlong_t)drrwbr->drr_key.ddk_prop,
(u_longlong_t)drrwbr->drr_offset,
(u_longlong_t)drrwbr->drr_length,
(u_longlong_t)drrwbr->drr_toguid,
(u_longlong_t)drrwbr->drr_refguid,
(u_longlong_t)drrwbr->drr_refobject,
(u_longlong_t)drrwbr->drr_refoffset);
}
break;
case DRR_FREE:
if (do_byteswap) {
drrf->drr_object = BSWAP_64(drrf->drr_object);
drrf->drr_offset = BSWAP_64(drrf->drr_offset);
drrf->drr_length = BSWAP_64(drrf->drr_length);
}
if (verbose) {
(void) printf("FREE object = %llu "
"offset = %llu length = %lld\n",
(u_longlong_t)drrf->drr_object,
(u_longlong_t)drrf->drr_offset,
(longlong_t)drrf->drr_length);
}
break;
case DRR_SPILL:
if (do_byteswap) {
drrs->drr_object = BSWAP_64(drrs->drr_object);
drrs->drr_length = BSWAP_64(drrs->drr_length);
}
if (verbose) {
(void) printf("SPILL block for object = %llu "
"length = %llu\n", drrs->drr_object,
drrs->drr_length);
}
(void) ssread(buf, drrs->drr_length, &zc);
break;
}
pcksum = zc;
}
free(buf);
/* Print final summary */
(void) printf("SUMMARY:\n");
(void) printf("\tTotal DRR_BEGIN records = %lld\n",
(u_longlong_t)drr_record_count[DRR_BEGIN]);
(void) printf("\tTotal DRR_END records = %lld\n",
(u_longlong_t)drr_record_count[DRR_END]);
(void) printf("\tTotal DRR_OBJECT records = %lld\n",
(u_longlong_t)drr_record_count[DRR_OBJECT]);
(void) printf("\tTotal DRR_FREEOBJECTS records = %lld\n",
(u_longlong_t)drr_record_count[DRR_FREEOBJECTS]);
(void) printf("\tTotal DRR_WRITE records = %lld\n",
(u_longlong_t)drr_record_count[DRR_WRITE]);
(void) printf("\tTotal DRR_FREE records = %lld\n",
(u_longlong_t)drr_record_count[DRR_FREE]);
(void) printf("\tTotal DRR_SPILL records = %lld\n",
(u_longlong_t)drr_record_count[DRR_SPILL]);
(void) printf("\tTotal records = %lld\n",
(u_longlong_t)(drr_record_count[DRR_BEGIN] +
drr_record_count[DRR_OBJECT] +
drr_record_count[DRR_FREEOBJECTS] +
drr_record_count[DRR_WRITE] +
drr_record_count[DRR_FREE] +
drr_record_count[DRR_SPILL] +
drr_record_count[DRR_END]));
(void) printf("\tTotal write size = %lld (0x%llx)\n",
(u_longlong_t)total_write_size, (u_longlong_t)total_write_size);
(void) printf("\tTotal stream length = %lld (0x%llx)\n",
(u_longlong_t)total_stream_len, (u_longlong_t)total_stream_len);
return (0);
}

File diff suppressed because it is too large Load Diff

View File

@ -20,15 +20,12 @@
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _SYNCH_H
#define _SYNCH_H
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* synch.h:
* definitions needed to use the thread synchronization interface
@ -243,10 +240,17 @@ int sema_trywait();
#ifdef __STDC__
int _sema_held(sema_t *);
int _rw_read_held(rwlock_t *);
int _rw_write_held(rwlock_t *);
int _mutex_held(mutex_t *);
/*
* The *_held() functions apply equally well to Solaris threads
* and to Posix threads synchronization objects, but the formal
* type declarations are different, so we just declare the argument
* to each *_held() function to be a void *, expecting that they will
* be called with the proper type of argument in each case.
*/
int _sema_held(void *); /* sema_t or sem_t */
int _rw_read_held(void *); /* rwlock_t or pthread_rwlock_t */
int _rw_write_held(void *); /* rwlock_t or pthread_rwlock_t */
int _mutex_held(void *); /* mutex_t or pthread_mutex_t */
#else /* __STDC__ */
@ -257,6 +261,13 @@ int _mutex_held();
#endif /* __STDC__ */
/* Pause API */
#ifdef __STDC__
void smt_pause(void);
#else /* __STDC__ */
void smt_pause();
#endif /* __STDC__ */
#endif /* _ASM */
#ifdef __cplusplus

View File

@ -19,15 +19,15 @@
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <solaris.h>
#include <inttypes.h>
#include <unistd.h>
#include <strings.h>
#include <libintl.h>
#include <stdarg.h>
#include "libnvpair.h"
/*
@ -38,21 +38,531 @@
* between kernel and userland, and possibly saving onto disk files.
*/
/*
* Print control structure.
*/
#define DEFINEOP(opname, vtype) \
struct { \
int (*op)(struct nvlist_prtctl *, void *, nvlist_t *, \
const char *, vtype); \
void *arg; \
} opname
#define DEFINEARROP(opname, vtype) \
struct { \
int (*op)(struct nvlist_prtctl *, void *, nvlist_t *, \
const char *, vtype, uint_t); \
void *arg; \
} opname
struct nvlist_printops {
DEFINEOP(print_boolean, int);
DEFINEOP(print_boolean_value, boolean_t);
DEFINEOP(print_byte, uchar_t);
DEFINEOP(print_int8, int8_t);
DEFINEOP(print_uint8, uint8_t);
DEFINEOP(print_int16, int16_t);
DEFINEOP(print_uint16, uint16_t);
DEFINEOP(print_int32, int32_t);
DEFINEOP(print_uint32, uint32_t);
DEFINEOP(print_int64, int64_t);
DEFINEOP(print_uint64, uint64_t);
DEFINEOP(print_double, double);
DEFINEOP(print_string, char *);
DEFINEOP(print_hrtime, hrtime_t);
DEFINEOP(print_nvlist, nvlist_t *);
DEFINEARROP(print_boolean_array, boolean_t *);
DEFINEARROP(print_byte_array, uchar_t *);
DEFINEARROP(print_int8_array, int8_t *);
DEFINEARROP(print_uint8_array, uint8_t *);
DEFINEARROP(print_int16_array, int16_t *);
DEFINEARROP(print_uint16_array, uint16_t *);
DEFINEARROP(print_int32_array, int32_t *);
DEFINEARROP(print_uint32_array, uint32_t *);
DEFINEARROP(print_int64_array, int64_t *);
DEFINEARROP(print_uint64_array, uint64_t *);
DEFINEARROP(print_string_array, char **);
DEFINEARROP(print_nvlist_array, nvlist_t **);
};
struct nvlist_prtctl {
FILE *nvprt_fp; /* output destination */
enum nvlist_indent_mode nvprt_indent_mode; /* see above */
int nvprt_indent; /* absolute indent, or tab depth */
int nvprt_indentinc; /* indent or tab increment */
const char *nvprt_nmfmt; /* member name format, max one %s */
const char *nvprt_eomfmt; /* after member format, e.g. "\n" */
const char *nvprt_btwnarrfmt; /* between array members */
int nvprt_btwnarrfmt_nl; /* nvprt_eoamfmt includes newline? */
struct nvlist_printops *nvprt_dfltops;
struct nvlist_printops *nvprt_custops;
};
#define DFLTPRTOP(pctl, type) \
((pctl)->nvprt_dfltops->print_##type.op)
#define DFLTPRTOPARG(pctl, type) \
((pctl)->nvprt_dfltops->print_##type.arg)
#define CUSTPRTOP(pctl, type) \
((pctl)->nvprt_custops->print_##type.op)
#define CUSTPRTOPARG(pctl, type) \
((pctl)->nvprt_custops->print_##type.arg)
#define RENDER(pctl, type, nvl, name, val) \
{ \
int done = 0; \
if ((pctl)->nvprt_custops && CUSTPRTOP(pctl, type)) { \
done = CUSTPRTOP(pctl, type)(pctl, \
CUSTPRTOPARG(pctl, type), nvl, name, val); \
} \
if (!done) { \
(void) DFLTPRTOP(pctl, type)(pctl, \
DFLTPRTOPARG(pctl, type), nvl, name, val); \
} \
(void) fprintf(pctl->nvprt_fp, pctl->nvprt_eomfmt); \
}
#define ARENDER(pctl, type, nvl, name, arrp, count) \
{ \
int done = 0; \
if ((pctl)->nvprt_custops && CUSTPRTOP(pctl, type)) { \
done = CUSTPRTOP(pctl, type)(pctl, \
CUSTPRTOPARG(pctl, type), nvl, name, arrp, count); \
} \
if (!done) { \
(void) DFLTPRTOP(pctl, type)(pctl, \
DFLTPRTOPARG(pctl, type), nvl, name, arrp, count); \
} \
(void) fprintf(pctl->nvprt_fp, pctl->nvprt_eomfmt); \
}
static void nvlist_print_with_indent(nvlist_t *, nvlist_prtctl_t);
/*
* ======================================================================
* | |
* | Indentation |
* | |
* ======================================================================
*/
static void
indent(FILE *fp, int depth)
indent(nvlist_prtctl_t pctl, int onemore)
{
while (depth-- > 0)
(void) fprintf(fp, "\t");
int depth;
switch (pctl->nvprt_indent_mode) {
case NVLIST_INDENT_ABS:
(void) fprintf(pctl->nvprt_fp, "%*s",
pctl->nvprt_indent + onemore * pctl->nvprt_indentinc, "");
break;
case NVLIST_INDENT_TABBED:
depth = pctl->nvprt_indent + onemore;
while (depth-- > 0)
(void) fprintf(pctl->nvprt_fp, "\t");
}
}
/*
* ======================================================================
* | |
* | Default nvlist member rendering functions. |
* | |
* ======================================================================
*/
/*
* Generate functions to print single-valued nvlist members.
*
* type_and_variant - suffix to form function name
* vtype - C type for the member value
* ptype - C type to cast value to for printing
* vfmt - format string for pair value, e.g "%d" or "0x%llx"
*/
#define NVLIST_PRTFUNC(type_and_variant, vtype, ptype, vfmt) \
static int \
nvprint_##type_and_variant(nvlist_prtctl_t pctl, void *private, \
nvlist_t *nvl, const char *name, vtype value) \
{ \
FILE *fp = pctl->nvprt_fp; \
NOTE(ARGUNUSED(private)) \
NOTE(ARGUNUSED(nvl)) \
indent(pctl, 1); \
(void) fprintf(fp, pctl->nvprt_nmfmt, name); \
(void) fprintf(fp, vfmt, (ptype)value); \
return (1); \
}
NVLIST_PRTFUNC(boolean, int, int, "%d")
NVLIST_PRTFUNC(boolean_value, boolean_t, int, "%d")
NVLIST_PRTFUNC(byte, uchar_t, uchar_t, "0x%2.2x")
NVLIST_PRTFUNC(int8, int8_t, int, "%d")
NVLIST_PRTFUNC(uint8, uint8_t, uint8_t, "0x%x")
NVLIST_PRTFUNC(int16, int16_t, int16_t, "%d")
NVLIST_PRTFUNC(uint16, uint16_t, uint16_t, "0x%x")
NVLIST_PRTFUNC(int32, int32_t, int32_t, "%d")
NVLIST_PRTFUNC(uint32, uint32_t, uint32_t, "0x%x")
NVLIST_PRTFUNC(int64, int64_t, longlong_t, "%lld")
NVLIST_PRTFUNC(uint64, uint64_t, u_longlong_t, "0x%llx")
NVLIST_PRTFUNC(double, double, double, "0x%llf")
NVLIST_PRTFUNC(string, char *, char *, "%s")
NVLIST_PRTFUNC(hrtime, hrtime_t, hrtime_t, "0x%llx")
/*
* Generate functions to print array-valued nvlist members.
*/
#define NVLIST_ARRPRTFUNC(type_and_variant, vtype, ptype, vfmt) \
static int \
nvaprint_##type_and_variant(nvlist_prtctl_t pctl, void *private, \
nvlist_t *nvl, const char *name, vtype *valuep, uint_t count) \
{ \
FILE *fp = pctl->nvprt_fp; \
uint_t i; \
NOTE(ARGUNUSED(private)) \
NOTE(ARGUNUSED(nvl)) \
for (i = 0; i < count; i++) { \
if (i == 0 || pctl->nvprt_btwnarrfmt_nl) { \
indent(pctl, 1); \
(void) fprintf(fp, pctl->nvprt_nmfmt, name); \
if (pctl->nvprt_btwnarrfmt_nl) \
(void) fprintf(fp, "[%d]: ", i); \
} \
if (i != 0) \
(void) fprintf(fp, pctl->nvprt_btwnarrfmt); \
(void) fprintf(fp, vfmt, (ptype)valuep[i]); \
} \
return (1); \
}
NVLIST_ARRPRTFUNC(boolean_array, boolean_t, boolean_t, "%d")
NVLIST_ARRPRTFUNC(byte_array, uchar_t, uchar_t, "0x%2.2x")
NVLIST_ARRPRTFUNC(int8_array, int8_t, int8_t, "%d")
NVLIST_ARRPRTFUNC(uint8_array, uint8_t, uint8_t, "0x%x")
NVLIST_ARRPRTFUNC(int16_array, int16_t, int16_t, "%d")
NVLIST_ARRPRTFUNC(uint16_array, uint16_t, uint16_t, "0x%x")
NVLIST_ARRPRTFUNC(int32_array, int32_t, int32_t, "%d")
NVLIST_ARRPRTFUNC(uint32_array, uint32_t, uint32_t, "0x%x")
NVLIST_ARRPRTFUNC(int64_array, int64_t, longlong_t, "%lld")
NVLIST_ARRPRTFUNC(uint64_array, uint64_t, u_longlong_t, "0x%llx")
NVLIST_ARRPRTFUNC(string_array, char *, char *, "%s")
/*ARGSUSED*/
static int
nvprint_nvlist(nvlist_prtctl_t pctl, void *private,
nvlist_t *nvl, const char *name, nvlist_t *value)
{
FILE *fp = pctl->nvprt_fp;
indent(pctl, 1);
(void) fprintf(fp, "%s = (embedded nvlist)\n", name);
pctl->nvprt_indent += pctl->nvprt_indentinc;
nvlist_print_with_indent(value, pctl);
pctl->nvprt_indent -= pctl->nvprt_indentinc;
indent(pctl, 1);
(void) fprintf(fp, "(end %s)\n", name);
return (1);
}
/*ARGSUSED*/
static int
nvaprint_nvlist_array(nvlist_prtctl_t pctl, void *private,
nvlist_t *nvl, const char *name, nvlist_t **valuep, uint_t count)
{
FILE *fp = pctl->nvprt_fp;
uint_t i;
indent(pctl, 1);
(void) fprintf(fp, "%s = (array of embedded nvlists)\n", name);
for (i = 0; i < count; i++) {
indent(pctl, 1);
(void) fprintf(fp, "(start %s[%d])\n", name, i);
pctl->nvprt_indent += pctl->nvprt_indentinc;
nvlist_print_with_indent(valuep[i], pctl);
pctl->nvprt_indent -= pctl->nvprt_indentinc;
indent(pctl, 1);
(void) fprintf(fp, "(end %s[%d])\n", name, i);
}
return (1);
}
/*
* ======================================================================
* | |
* | Interfaces that allow control over formatting. |
* | |
* ======================================================================
*/
void
nvlist_prtctl_setdest(nvlist_prtctl_t pctl, FILE *fp)
{
pctl->nvprt_fp = fp;
}
FILE *
nvlist_prtctl_getdest(nvlist_prtctl_t pctl)
{
return (pctl->nvprt_fp);
}
void
nvlist_prtctl_setindent(nvlist_prtctl_t pctl, enum nvlist_indent_mode mode,
int start, int inc)
{
if (mode < NVLIST_INDENT_ABS || mode > NVLIST_INDENT_TABBED)
mode = NVLIST_INDENT_TABBED;
if (start < 0)
start = 0;
if (inc < 0)
inc = 1;
pctl->nvprt_indent_mode = mode;
pctl->nvprt_indent = start;
pctl->nvprt_indentinc = inc;
}
void
nvlist_prtctl_doindent(nvlist_prtctl_t pctl, int onemore)
{
indent(pctl, onemore);
}
void
nvlist_prtctl_setfmt(nvlist_prtctl_t pctl, enum nvlist_prtctl_fmt which,
const char *fmt)
{
switch (which) {
case NVLIST_FMT_MEMBER_NAME:
if (fmt == NULL)
fmt = "%s = ";
pctl->nvprt_nmfmt = fmt;
break;
case NVLIST_FMT_MEMBER_POSTAMBLE:
if (fmt == NULL)
fmt = "\n";
pctl->nvprt_eomfmt = fmt;
break;
case NVLIST_FMT_BTWN_ARRAY:
if (fmt == NULL) {
pctl->nvprt_btwnarrfmt = " ";
pctl->nvprt_btwnarrfmt_nl = 0;
} else {
pctl->nvprt_btwnarrfmt = fmt;
pctl->nvprt_btwnarrfmt_nl = (strstr(fmt, "\n") != NULL);
}
break;
default:
break;
}
}
void
nvlist_prtctl_dofmt(nvlist_prtctl_t pctl, enum nvlist_prtctl_fmt which, ...)
{
FILE *fp = pctl->nvprt_fp;
va_list ap;
char *name;
va_start(ap, which);
switch (which) {
case NVLIST_FMT_MEMBER_NAME:
name = va_arg(ap, char *);
(void) fprintf(fp, pctl->nvprt_nmfmt, name);
break;
case NVLIST_FMT_MEMBER_POSTAMBLE:
(void) fprintf(fp, pctl->nvprt_eomfmt);
break;
case NVLIST_FMT_BTWN_ARRAY:
(void) fprintf(fp, pctl->nvprt_btwnarrfmt); \
break;
default:
break;
}
va_end(ap);
}
/*
* ======================================================================
* | |
* | Interfaces to allow appointment of replacement rendering functions.|
* | |
* ======================================================================
*/
#define NVLIST_PRINTCTL_REPLACE(type, vtype) \
void \
nvlist_prtctlop_##type(nvlist_prtctl_t pctl, \
int (*func)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype), \
void *private) \
{ \
CUSTPRTOP(pctl, type) = func; \
CUSTPRTOPARG(pctl, type) = private; \
}
NVLIST_PRINTCTL_REPLACE(boolean, int)
NVLIST_PRINTCTL_REPLACE(boolean_value, boolean_t)
NVLIST_PRINTCTL_REPLACE(byte, uchar_t)
NVLIST_PRINTCTL_REPLACE(int8, int8_t)
NVLIST_PRINTCTL_REPLACE(uint8, uint8_t)
NVLIST_PRINTCTL_REPLACE(int16, int16_t)
NVLIST_PRINTCTL_REPLACE(uint16, uint16_t)
NVLIST_PRINTCTL_REPLACE(int32, int32_t)
NVLIST_PRINTCTL_REPLACE(uint32, uint32_t)
NVLIST_PRINTCTL_REPLACE(int64, int64_t)
NVLIST_PRINTCTL_REPLACE(uint64, uint64_t)
NVLIST_PRINTCTL_REPLACE(double, double)
NVLIST_PRINTCTL_REPLACE(string, char *)
NVLIST_PRINTCTL_REPLACE(hrtime, hrtime_t)
NVLIST_PRINTCTL_REPLACE(nvlist, nvlist_t *)
#define NVLIST_PRINTCTL_AREPLACE(type, vtype) \
void \
nvlist_prtctlop_##type(nvlist_prtctl_t pctl, \
int (*func)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype, \
uint_t), void *private) \
{ \
CUSTPRTOP(pctl, type) = func; \
CUSTPRTOPARG(pctl, type) = private; \
}
NVLIST_PRINTCTL_AREPLACE(boolean_array, boolean_t *)
NVLIST_PRINTCTL_AREPLACE(byte_array, uchar_t *)
NVLIST_PRINTCTL_AREPLACE(int8_array, int8_t *)
NVLIST_PRINTCTL_AREPLACE(uint8_array, uint8_t *)
NVLIST_PRINTCTL_AREPLACE(int16_array, int16_t *)
NVLIST_PRINTCTL_AREPLACE(uint16_array, uint16_t *)
NVLIST_PRINTCTL_AREPLACE(int32_array, int32_t *)
NVLIST_PRINTCTL_AREPLACE(uint32_array, uint32_t *)
NVLIST_PRINTCTL_AREPLACE(int64_array, int64_t *)
NVLIST_PRINTCTL_AREPLACE(uint64_array, uint64_t *)
NVLIST_PRINTCTL_AREPLACE(string_array, char **)
NVLIST_PRINTCTL_AREPLACE(nvlist_array, nvlist_t **)
/*
* ======================================================================
* | |
* | Interfaces to manage nvlist_prtctl_t cookies. |
* | |
* ======================================================================
*/
static const struct nvlist_printops defprtops = {
{ nvprint_boolean, NULL },
{ nvprint_boolean_value, NULL },
{ nvprint_byte, NULL },
{ nvprint_int8, NULL },
{ nvprint_uint8, NULL },
{ nvprint_int16, NULL },
{ nvprint_uint16, NULL },
{ nvprint_int32, NULL },
{ nvprint_uint32, NULL },
{ nvprint_int64, NULL },
{ nvprint_uint64, NULL },
{ nvprint_double, NULL },
{ nvprint_string, NULL },
{ nvprint_hrtime, NULL },
{ nvprint_nvlist, NULL },
{ nvaprint_boolean_array, NULL },
{ nvaprint_byte_array, NULL },
{ nvaprint_int8_array, NULL },
{ nvaprint_uint8_array, NULL },
{ nvaprint_int16_array, NULL },
{ nvaprint_uint16_array, NULL },
{ nvaprint_int32_array, NULL },
{ nvaprint_uint32_array, NULL },
{ nvaprint_int64_array, NULL },
{ nvaprint_uint64_array, NULL },
{ nvaprint_string_array, NULL },
{ nvaprint_nvlist_array, NULL },
};
static void
prtctl_defaults(FILE *fp, struct nvlist_prtctl *pctl,
struct nvlist_printops *ops)
{
pctl->nvprt_fp = fp;
pctl->nvprt_indent_mode = NVLIST_INDENT_TABBED;
pctl->nvprt_indent = 0;
pctl->nvprt_indentinc = 1;
pctl->nvprt_nmfmt = "%s = ";
pctl->nvprt_eomfmt = "\n";
pctl->nvprt_btwnarrfmt = " ";
pctl->nvprt_btwnarrfmt_nl = 0;
pctl->nvprt_dfltops = (struct nvlist_printops *)&defprtops;
pctl->nvprt_custops = ops;
}
nvlist_prtctl_t
nvlist_prtctl_alloc(void)
{
struct nvlist_prtctl *pctl;
struct nvlist_printops *ops;
if ((pctl = malloc(sizeof (*pctl))) == NULL)
return (NULL);
if ((ops = calloc(1, sizeof (*ops))) == NULL) {
free(pctl);
return (NULL);
}
prtctl_defaults(stdout, pctl, ops);
return (pctl);
}
void
nvlist_prtctl_free(nvlist_prtctl_t pctl)
{
if (pctl != NULL) {
free(pctl->nvprt_custops);
free(pctl);
}
}
/*
* ======================================================================
* | |
* | Top-level print request interfaces. |
* | |
* ======================================================================
*/
/*
* nvlist_print - Prints elements in an event buffer
*/
static
void
nvlist_print_with_indent(FILE *fp, nvlist_t *nvl, int depth)
static void
nvlist_print_with_indent(nvlist_t *nvl, nvlist_prtctl_t pctl)
{
int i;
FILE *fp = pctl->nvprt_fp;
char *name;
uint_t nelem;
nvpair_t *nvp;
@ -60,7 +570,7 @@ nvlist_print_with_indent(FILE *fp, nvlist_t *nvl, int depth)
if (nvl == NULL)
return;
indent(fp, depth);
indent(pctl, 0);
(void) fprintf(fp, "nvlist version: %d\n", NVL_VERSION(nvl));
nvp = nvlist_next_nvpair(nvl, NULL);
@ -68,199 +578,174 @@ nvlist_print_with_indent(FILE *fp, nvlist_t *nvl, int depth)
while (nvp) {
data_type_t type = nvpair_type(nvp);
indent(fp, depth);
name = nvpair_name(nvp);
(void) fprintf(fp, "\t%s =", name);
nelem = 0;
switch (type) {
case DATA_TYPE_BOOLEAN: {
(void) fprintf(fp, " 1");
RENDER(pctl, boolean, nvl, name, 1);
break;
}
case DATA_TYPE_BOOLEAN_VALUE: {
boolean_t val;
(void) nvpair_value_boolean_value(nvp, &val);
(void) fprintf(fp, " %d", val);
RENDER(pctl, boolean_value, nvl, name, val);
break;
}
case DATA_TYPE_BYTE: {
uchar_t val;
(void) nvpair_value_byte(nvp, &val);
(void) fprintf(fp, " 0x%2.2x", val);
RENDER(pctl, byte, nvl, name, val);
break;
}
case DATA_TYPE_INT8: {
int8_t val;
(void) nvpair_value_int8(nvp, &val);
(void) fprintf(fp, " %d", val);
RENDER(pctl, int8, nvl, name, val);
break;
}
case DATA_TYPE_UINT8: {
uint8_t val;
(void) nvpair_value_uint8(nvp, &val);
(void) fprintf(fp, " 0x%x", val);
RENDER(pctl, uint8, nvl, name, val);
break;
}
case DATA_TYPE_INT16: {
int16_t val;
(void) nvpair_value_int16(nvp, &val);
(void) fprintf(fp, " %d", val);
RENDER(pctl, int16, nvl, name, val);
break;
}
case DATA_TYPE_UINT16: {
uint16_t val;
(void) nvpair_value_uint16(nvp, &val);
(void) fprintf(fp, " 0x%x", val);
RENDER(pctl, uint16, nvl, name, val);
break;
}
case DATA_TYPE_INT32: {
int32_t val;
(void) nvpair_value_int32(nvp, &val);
(void) fprintf(fp, " %d", val);
RENDER(pctl, int32, nvl, name, val);
break;
}
case DATA_TYPE_UINT32: {
uint32_t val;
(void) nvpair_value_uint32(nvp, &val);
(void) fprintf(fp, " 0x%x", val);
RENDER(pctl, uint32, nvl, name, val);
break;
}
case DATA_TYPE_INT64: {
int64_t val;
(void) nvpair_value_int64(nvp, &val);
(void) fprintf(fp, " %lld", (longlong_t)val);
RENDER(pctl, int64, nvl, name, val);
break;
}
case DATA_TYPE_UINT64: {
uint64_t val;
(void) nvpair_value_uint64(nvp, &val);
(void) fprintf(fp, " 0x%llx", (u_longlong_t)val);
RENDER(pctl, uint64, nvl, name, val);
break;
}
case DATA_TYPE_DOUBLE: {
double val;
(void) nvpair_value_double(nvp, &val);
(void) fprintf(fp, " 0x%llf", val);
RENDER(pctl, double, nvl, name, val);
break;
}
case DATA_TYPE_STRING: {
char *val;
(void) nvpair_value_string(nvp, &val);
(void) fprintf(fp, " %s", val);
RENDER(pctl, string, nvl, name, val);
break;
}
case DATA_TYPE_BOOLEAN_ARRAY: {
boolean_t *val;
(void) nvpair_value_boolean_array(nvp, &val, &nelem);
for (i = 0; i < nelem; i++)
(void) fprintf(fp, " %d", val[i]);
ARENDER(pctl, boolean_array, nvl, name, val, nelem);
break;
}
case DATA_TYPE_BYTE_ARRAY: {
uchar_t *val;
(void) nvpair_value_byte_array(nvp, &val, &nelem);
for (i = 0; i < nelem; i++)
(void) fprintf(fp, " 0x%2.2x", val[i]);
ARENDER(pctl, byte_array, nvl, name, val, nelem);
break;
}
case DATA_TYPE_INT8_ARRAY: {
int8_t *val;
(void) nvpair_value_int8_array(nvp, &val, &nelem);
for (i = 0; i < nelem; i++)
(void) fprintf(fp, " %d", val[i]);
ARENDER(pctl, int8_array, nvl, name, val, nelem);
break;
}
case DATA_TYPE_UINT8_ARRAY: {
uint8_t *val;
(void) nvpair_value_uint8_array(nvp, &val, &nelem);
for (i = 0; i < nelem; i++)
(void) fprintf(fp, " 0x%x", val[i]);
ARENDER(pctl, uint8_array, nvl, name, val, nelem);
break;
}
case DATA_TYPE_INT16_ARRAY: {
int16_t *val;
(void) nvpair_value_int16_array(nvp, &val, &nelem);
for (i = 0; i < nelem; i++)
(void) fprintf(fp, " %d", val[i]);
ARENDER(pctl, int16_array, nvl, name, val, nelem);
break;
}
case DATA_TYPE_UINT16_ARRAY: {
uint16_t *val;
(void) nvpair_value_uint16_array(nvp, &val, &nelem);
for (i = 0; i < nelem; i++)
(void) fprintf(fp, " 0x%x", val[i]);
ARENDER(pctl, uint16_array, nvl, name, val, nelem);
break;
}
case DATA_TYPE_INT32_ARRAY: {
int32_t *val;
(void) nvpair_value_int32_array(nvp, &val, &nelem);
for (i = 0; i < nelem; i++)
(void) fprintf(fp, " %d", val[i]);
ARENDER(pctl, int32_array, nvl, name, val, nelem);
break;
}
case DATA_TYPE_UINT32_ARRAY: {
uint32_t *val;
(void) nvpair_value_uint32_array(nvp, &val, &nelem);
for (i = 0; i < nelem; i++)
(void) fprintf(fp, " 0x%x", val[i]);
ARENDER(pctl, uint32_array, nvl, name, val, nelem);
break;
}
case DATA_TYPE_INT64_ARRAY: {
int64_t *val;
(void) nvpair_value_int64_array(nvp, &val, &nelem);
for (i = 0; i < nelem; i++)
(void) fprintf(fp, " %lld", (longlong_t)val[i]);
ARENDER(pctl, int64_array, nvl, name, val, nelem);
break;
}
case DATA_TYPE_UINT64_ARRAY: {
uint64_t *val;
(void) nvpair_value_uint64_array(nvp, &val, &nelem);
for (i = 0; i < nelem; i++)
(void) fprintf(fp, " 0x%llx",
(u_longlong_t)val[i]);
ARENDER(pctl, uint64_array, nvl, name, val, nelem);
break;
}
case DATA_TYPE_STRING_ARRAY: {
char **val;
(void) nvpair_value_string_array(nvp, &val, &nelem);
for (i = 0; i < nelem; i++)
(void) fprintf(fp, " %s", val[i]);
ARENDER(pctl, string_array, nvl, name, val, nelem);
break;
}
case DATA_TYPE_HRTIME: {
hrtime_t val;
(void) nvpair_value_hrtime(nvp, &val);
(void) fprintf(fp, " 0x%llx", val);
RENDER(pctl, hrtime, nvl, name, val);
break;
}
case DATA_TYPE_NVLIST: {
nvlist_t *val;
(void) nvpair_value_nvlist(nvp, &val);
(void) fprintf(fp, " (embedded nvlist)\n");
nvlist_print_with_indent(fp, val, depth + 1);
indent(fp, depth + 1);
(void) fprintf(fp, "(end %s)\n", name);
RENDER(pctl, nvlist, nvl, name, val);
break;
}
case DATA_TYPE_NVLIST_ARRAY: {
nvlist_t **val;
(void) nvpair_value_nvlist_array(nvp, &val, &nelem);
(void) fprintf(fp, " (array of embedded nvlists)\n");
for (i = 0; i < nelem; i++) {
indent(fp, depth + 1);
(void) fprintf(fp,
"(start %s[%d])\n", name, i);
nvlist_print_with_indent(fp, val[i], depth + 1);
indent(fp, depth + 1);
(void) fprintf(fp, "(end %s[%d])\n", name, i);
}
ARENDER(pctl, nvlist_array, nvl, name, val, nelem);
break;
}
default:
(void) fprintf(fp, " unknown data type (%d)", type);
break;
}
(void) fprintf(fp, "\n");
nvp = nvlist_next_nvpair(nvl, nvp);
}
}
@ -268,9 +753,175 @@ nvlist_print_with_indent(FILE *fp, nvlist_t *nvl, int depth)
void
nvlist_print(FILE *fp, nvlist_t *nvl)
{
nvlist_print_with_indent(fp, nvl, 0);
struct nvlist_prtctl pc;
prtctl_defaults(fp, &pc, NULL);
nvlist_print_with_indent(nvl, &pc);
}
void
nvlist_prt(nvlist_t *nvl, nvlist_prtctl_t pctl)
{
nvlist_print_with_indent(nvl, pctl);
}
#define NVP(elem, type, vtype, ptype, format) { \
vtype value; \
\
(void) nvpair_value_##type(elem, &value); \
(void) printf("%*s%s: " format "\n", indent, "", \
nvpair_name(elem), (ptype)value); \
}
#define NVPA(elem, type, vtype, ptype, format) { \
uint_t i, count; \
vtype *value; \
\
(void) nvpair_value_##type(elem, &value, &count); \
for (i = 0; i < count; i++) { \
(void) printf("%*s%s[%d]: " format "\n", indent, "", \
nvpair_name(elem), i, (ptype)value[i]); \
} \
}
/*
* Similar to nvlist_print() but handles arrays slightly differently.
*/
void
dump_nvlist(nvlist_t *list, int indent)
{
nvpair_t *elem = NULL;
boolean_t bool_value;
nvlist_t *nvlist_value;
nvlist_t **nvlist_array_value;
uint_t i, count;
if (list == NULL) {
return;
}
while ((elem = nvlist_next_nvpair(list, elem)) != NULL) {
switch (nvpair_type(elem)) {
case DATA_TYPE_BOOLEAN_VALUE:
(void) nvpair_value_boolean_value(elem, &bool_value);
(void) printf("%*s%s: %s\n", indent, "",
nvpair_name(elem), bool_value ? "true" : "false");
break;
case DATA_TYPE_BYTE:
NVP(elem, byte, uchar_t, int, "%u");
break;
case DATA_TYPE_INT8:
NVP(elem, int8, int8_t, int, "%d");
break;
case DATA_TYPE_UINT8:
NVP(elem, uint8, uint8_t, int, "%u");
break;
case DATA_TYPE_INT16:
NVP(elem, int16, int16_t, int, "%d");
break;
case DATA_TYPE_UINT16:
NVP(elem, uint16, uint16_t, int, "%u");
break;
case DATA_TYPE_INT32:
NVP(elem, int32, int32_t, long, "%ld");
break;
case DATA_TYPE_UINT32:
NVP(elem, uint32, uint32_t, ulong_t, "%lu");
break;
case DATA_TYPE_INT64:
NVP(elem, int64, int64_t, longlong_t, "%lld");
break;
case DATA_TYPE_UINT64:
NVP(elem, uint64, uint64_t, u_longlong_t, "%llu");
break;
case DATA_TYPE_STRING:
NVP(elem, string, char *, char *, "'%s'");
break;
case DATA_TYPE_BYTE_ARRAY:
NVPA(elem, byte_array, uchar_t, int, "%u");
break;
case DATA_TYPE_INT8_ARRAY:
NVPA(elem, int8_array, int8_t, int, "%d");
break;
case DATA_TYPE_UINT8_ARRAY:
NVPA(elem, uint8_array, uint8_t, int, "%u");
break;
case DATA_TYPE_INT16_ARRAY:
NVPA(elem, int16_array, int16_t, int, "%d");
break;
case DATA_TYPE_UINT16_ARRAY:
NVPA(elem, uint16_array, uint16_t, int, "%u");
break;
case DATA_TYPE_INT32_ARRAY:
NVPA(elem, int32_array, int32_t, long, "%ld");
break;
case DATA_TYPE_UINT32_ARRAY:
NVPA(elem, uint32_array, uint32_t, ulong_t, "%lu");
break;
case DATA_TYPE_INT64_ARRAY:
NVPA(elem, int64_array, int64_t, longlong_t, "%lld");
break;
case DATA_TYPE_UINT64_ARRAY:
NVPA(elem, uint64_array, uint64_t, u_longlong_t,
"%llu");
break;
case DATA_TYPE_STRING_ARRAY:
NVPA(elem, string_array, char *, char *, "'%s'");
break;
case DATA_TYPE_NVLIST:
(void) nvpair_value_nvlist(elem, &nvlist_value);
(void) printf("%*s%s:\n", indent, "",
nvpair_name(elem));
dump_nvlist(nvlist_value, indent + 4);
break;
case DATA_TYPE_NVLIST_ARRAY:
(void) nvpair_value_nvlist_array(elem,
&nvlist_array_value, &count);
for (i = 0; i < count; i++) {
(void) printf("%*s%s[%u]:\n", indent, "",
nvpair_name(elem), i);
dump_nvlist(nvlist_array_value[i], indent + 4);
}
break;
default:
(void) printf(dgettext(TEXT_DOMAIN, "bad config type "
"%d for %s\n"), nvpair_type(elem),
nvpair_name(elem));
}
}
}
/*
* ======================================================================
* | |
* | Misc private interface. |
* | |
* ======================================================================
*/
/*
* Determine if string 'value' matches 'nvp' value. The 'value' string is
* converted, depending on the type of 'nvp', prior to match. For numeric

View File

@ -19,15 +19,12 @@
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _LIBNVPAIR_H
#define _LIBNVPAIR_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/nvpair.h>
#include <stdlib.h>
#include <stdio.h>
@ -37,9 +34,158 @@
extern "C" {
#endif
void nvlist_print(FILE *, nvlist_t *);
int nvpair_value_match(nvpair_t *, int, char *, char **);
int nvpair_value_match_regex(nvpair_t *, int, char *, regex_t *, char **);
/*
* All interfaces described in this file are private to Solaris, and
* are subject to change at any time and without notice. The public
* nvlist/nvpair interfaces, as documented in manpage sections 3NVPAIR,
* are all imported from <sys/nvpair.h> included above.
*/
extern int nvpair_value_match(nvpair_t *, int, char *, char **);
extern int nvpair_value_match_regex(nvpair_t *, int, char *, regex_t *,
char **);
extern void nvlist_print(FILE *, nvlist_t *);
extern void dump_nvlist(nvlist_t *, int);
/*
* Private nvlist printing interface that allows the caller some control
* over output rendering (as opposed to nvlist_print and dump_nvlist).
*
* Obtain an opaque nvlist_prtctl_t cookie using nvlist_prtctl_alloc
* (NULL on failure); on return the cookie is set up for default formatting
* and rendering. Quote the cookie in subsequent customisation functions and
* then pass the cookie to nvlist_prt to render the nvlist. Finally,
* use nvlist_prtctl_free to release the cookie.
*
* For all nvlist_lookup_xxx and nvlist_lookup_xxx_array functions
* we have a corresponding brace of functions that appoint replacement
* rendering functions:
*
* extern void nvlist_prtctl_xxx(nvlist_prtctl_t,
* void (*)(nvlist_prtctl_t ctl, void *private, const char *name,
* xxxtype value))
*
* and
*
* extern void nvlist_prtctl_xxx_array(nvlist_prtctl_t,
* void (*)(nvlist_prtctl_t ctl, void *private, const char *name,
* xxxtype value, uint_t count))
*
* where xxxtype is the C datatype corresponding to xxx, eg int8_t for "int8"
* and char * for "string". The function that is appointed to render the
* specified datatype receives as arguments the cookie, the nvlist
* member name, the value of that member (or a pointer for array function),
* and (for array rendering functions) a count of the number of elements.
*/
typedef struct nvlist_prtctl *nvlist_prtctl_t; /* opaque */
enum nvlist_indent_mode {
NVLIST_INDENT_ABS, /* Absolute indentation */
NVLIST_INDENT_TABBED /* Indent with tabstops */
};
extern nvlist_prtctl_t nvlist_prtctl_alloc(void);
extern void nvlist_prtctl_free(nvlist_prtctl_t);
extern void nvlist_prt(nvlist_t *, nvlist_prtctl_t);
/* Output stream */
extern void nvlist_prtctl_setdest(nvlist_prtctl_t, FILE *);
extern FILE *nvlist_prtctl_getdest(nvlist_prtctl_t);
/* Indentation mode, start indent, indent increment; default tabbed/0/1 */
extern void nvlist_prtctl_setindent(nvlist_prtctl_t, enum nvlist_indent_mode,
int, int);
extern void nvlist_prtctl_doindent(nvlist_prtctl_t, int);
enum nvlist_prtctl_fmt {
NVLIST_FMT_MEMBER_NAME, /* name fmt; default "%s = " */
NVLIST_FMT_MEMBER_POSTAMBLE, /* after nvlist member; default "\n" */
NVLIST_FMT_BTWN_ARRAY /* between array members; default " " */
};
extern void nvlist_prtctl_setfmt(nvlist_prtctl_t, enum nvlist_prtctl_fmt,
const char *);
extern void nvlist_prtctl_dofmt(nvlist_prtctl_t, enum nvlist_prtctl_fmt, ...);
/*
* Function prototypes for interfaces that appoint a new rendering function
* for single-valued nvlist members.
*
* A replacement function receives arguments as follows:
*
* nvlist_prtctl_t Print control structure; do not change preferences
* for this object from a print callback function.
*
* void * The function-private cookie argument registered
* when the replacement function was appointed.
*
* nvlist_t * The full nvlist that is being processed. The
* rendering function is called to render a single
* member (name and value passed as below) but it may
* want to reference or incorporate other aspects of
* the full nvlist.
*
* const char * Member name to render
*
* valtype Value of the member to render
*
* The function must return non-zero if it has rendered output for this
* member, or 0 if it wants to default to standard rendering for this
* one member.
*/
#define NVLIST_PRINTCTL_SVDECL(funcname, valtype) \
extern void funcname(nvlist_prtctl_t, \
int (*)(nvlist_prtctl_t, void *, nvlist_t *, const char *, valtype), \
void *)
NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_boolean, int);
NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_boolean_value, boolean_t);
NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_byte, uchar_t);
NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_int8, int8_t);
NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_uint8, uint8_t);
NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_int16, int16_t);
NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_uint16, uint16_t);
NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_int32, int32_t);
NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_uint32, uint32_t);
NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_int64, int64_t);
NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_uint64, uint64_t);
NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_double, double);
NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_string, char *);
NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_hrtime, hrtime_t);
NVLIST_PRINTCTL_SVDECL(nvlist_prtctlop_nvlist, nvlist_t *);
#undef NVLIST_PRINTCTL_SVDECL /* was just for "clarity" above */
/*
* Function prototypes for interfaces that appoint a new rendering function
* for array-valued nvlist members.
*
* One additional argument is taken: uint_t for the number of array elements
*
* Return values as above.
*/
#define NVLIST_PRINTCTL_AVDECL(funcname, vtype) \
extern void funcname(nvlist_prtctl_t, \
int (*)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype, uint_t), \
void *)
NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_boolean_array, boolean_t *);
NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_byte_array, uchar_t *);
NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_int8_array, int8_t *);
NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_uint8_array, uint8_t *);
NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_int16_array, int16_t *);
NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_uint16_array, uint16_t *);
NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_int32_array, int32_t *);
NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_uint32_array, uint32_t *);
NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_int64_array, int64_t *);
NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_uint64_array, uint64_t *);
NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_string_array, char **);
NVLIST_PRINTCTL_AVDECL(nvlist_prtctlop_nvlist_array, nvlist_t **);
#undef NVLIST_PRINTCTL_AVDECL /* was just for "clarity" above */
#ifdef __cplusplus
}

View File

@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _LIBUUTIL_H
@ -29,6 +28,7 @@
#include <solaris.h>
#include <sys/types.h>
#include <stdarg.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
@ -143,12 +143,21 @@ extern int uu_open_tmp(const char *dir, uint_t uflags);
/*
* Convenience functions.
*/
#define UU_NELEM(a) (sizeof (a) / sizeof ((a)[0]))
/*PRINTFLIKE1*/
extern char *uu_msprintf(const char *format, ...);
extern void *uu_zalloc(size_t);
extern char *uu_strdup(const char *);
extern void uu_free(void *);
extern boolean_t uu_strcaseeq(const char *a, const char *b);
extern boolean_t uu_streq(const char *a, const char *b);
extern char *uu_strndup(const char *s, size_t n);
extern boolean_t uu_strbw(const char *a, const char *b);
extern void *uu_memdup(const void *buf, size_t sz);
extern void uu_dump(FILE *out, const char *prefix, const void *buf, size_t len);
/*
* Comparison function type definition.
* Developers should be careful in their use of the _private argument. If you

View File

@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include "libuutil_common.h"
@ -67,6 +66,44 @@ uu_strdup(const char *str)
return (buf);
}
/*
* Duplicate up to n bytes of a string. Kind of sort of like
* strdup(strlcpy(s, n)).
*/
char *
uu_strndup(const char *s, size_t n)
{
size_t len;
char *p;
len = strnlen(s, n);
p = uu_zalloc(len + 1);
if (p == NULL)
return (NULL);
if (len > 0)
(void) memcpy(p, s, len);
p[len] = '\0';
return (p);
}
/*
* Duplicate a block of memory. Combines malloc with memcpy, much as
* strdup combines malloc, strlen, and strcpy.
*/
void *
uu_memdup(const void *buf, size_t sz)
{
void *p;
p = uu_zalloc(sz);
if (p == NULL)
return (NULL);
(void) memcpy(p, buf, sz);
return (p);
}
char *
uu_msprintf(const char *format, ...)
{

View File

@ -20,12 +20,9 @@
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "libuutil_common.h"
#include <assert.h>
@ -39,6 +36,7 @@
#include <sys/debug.h>
#include <thread.h>
#include <unistd.h>
#include <ctype.h>
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
@ -248,3 +246,30 @@ uu_init(void)
{
(void) pthread_atfork(uu_lockup, uu_release, uu_release_child);
}
/*
* Dump a block of memory in hex+ascii, for debugging
*/
void
uu_dump(FILE *out, const char *prefix, const void *buf, size_t len)
{
const unsigned char *p = buf;
int i;
for (i = 0; i < len; i += 16) {
int j;
(void) fprintf(out, "%s", prefix);
for (j = 0; j < 16 && i + j < len; j++) {
(void) fprintf(out, "%2.2x ", p[i + j]);
}
for (; j < 16; j++) {
(void) fprintf(out, " ");
}
for (j = 0; j < 16 && i + j < len; j++) {
(void) fprintf(out, "%c",
isprint(p[i + j]) ? p[i + j] : '.');
}
(void) fprintf(out, "\n");
}
}

View File

@ -0,0 +1,56 @@
/*
* CDDL HEADER START
*
* 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]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
* String helper functions
*/
#include <string.h>
#include <sys/types.h>
#include <stdio.h>
#include <malloc.h>
#include <ctype.h>
#include "libuutil.h"
/* Return true if strings are equal */
boolean_t
uu_streq(const char *a, const char *b)
{
return (strcmp(a, b) == 0);
}
/* Return true if strings are equal, case-insensitively */
boolean_t
uu_strcaseeq(const char *a, const char *b)
{
return (strcasecmp(a, b) == 0);
}
/* Return true if string a Begins With string b */
boolean_t
uu_strbw(const char *a, const char *b)
{
return (strncmp(a, b, strlen(b)) == 0);
}

View File

@ -20,8 +20,8 @@
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _LIBZFS_H
@ -66,7 +66,6 @@ enum {
EZFS_BADSTREAM, /* bad backup stream */
EZFS_DSREADONLY, /* dataset is readonly */
EZFS_VOLTOOBIG, /* volume is too large for 32-bit system */
EZFS_VOLHASDATA, /* volume already contains data */
EZFS_INVALIDNAME, /* invalid dataset name */
EZFS_BADRESTORE, /* unable to restore to destination */
EZFS_BADBACKUP, /* backup failed */
@ -85,17 +84,15 @@ enum {
EZFS_UMOUNTFAILED, /* failed to unmount dataset */
EZFS_UNSHARENFSFAILED, /* unshare(1M) failed */
EZFS_SHARENFSFAILED, /* share(1M) failed */
EZFS_DEVLINKS, /* failed to create zvol links */
EZFS_PERM, /* permission denied */
EZFS_NOSPC, /* out of space */
EZFS_FAULT, /* bad address */
EZFS_IO, /* I/O error */
EZFS_INTR, /* signal received */
EZFS_ISSPARE, /* device is a hot spare */
EZFS_INVALCONFIG, /* invalid vdev configuration */
EZFS_RECURSIVE, /* recursive dependency */
EZFS_NOHISTORY, /* no history object */
EZFS_UNSHAREISCSIFAILED, /* iscsitgtd failed request to unshare */
EZFS_SHAREISCSIFAILED, /* iscsitgtd failed request to share */
EZFS_POOLPROPS, /* couldn't retrieve pool props */
EZFS_POOL_NOTSUP, /* ops not supported for this type of pool */
EZFS_POOL_INVALARG, /* invalid argument for this pool operation */
@ -103,12 +100,10 @@ enum {
EZFS_OPENFAILED, /* open of device failed */
EZFS_NOCAP, /* couldn't get capacity */
EZFS_LABELFAILED, /* write of label failed */
EZFS_ISCSISVCUNAVAIL, /* iscsi service unavailable */
EZFS_BADWHO, /* invalid permission who */
EZFS_BADPERM, /* invalid permission */
EZFS_BADPERMSET, /* invalid permission set name */
EZFS_NODELEGATION, /* delegated administration is disabled */
EZFS_PERMRDONLY, /* pemissions are readonly */
EZFS_UNSHARESMBFAILED, /* failed to unshare over smb */
EZFS_SHARESMBFAILED, /* failed to share over smb */
EZFS_BADCACHE, /* bad cache file */
@ -117,6 +112,17 @@ enum {
EZFS_NOTSUP, /* ops not supported on this dataset */
EZFS_ACTIVE_SPARE, /* pool has active shared spare devices */
EZFS_UNPLAYED_LOGS, /* log device has unplayed logs */
EZFS_REFTAG_RELE, /* snapshot release: tag not found */
EZFS_REFTAG_HOLD, /* snapshot hold: tag already exists */
EZFS_TAGTOOLONG, /* snapshot hold/rele: tag too long */
EZFS_PIPEFAILED, /* pipe create failed */
EZFS_THREADCREATEFAILED, /* thread create failed */
EZFS_POSTSPLIT_ONLINE, /* onlining a disk after splitting it */
EZFS_SCRUBBING, /* currently scrubbing */
EZFS_NO_SCRUB, /* no active scrub */
EZFS_DIFF, /* general failure of zfs diff */
EZFS_DIFFDATA, /* bad zfs diff data */
EZFS_POOLREADONLY, /* pool is in read-only mode */
EZFS_UNKNOWN
};
@ -211,11 +217,19 @@ extern int zpool_create(libzfs_handle_t *, const char *, nvlist_t *,
extern int zpool_destroy(zpool_handle_t *);
extern int zpool_add(zpool_handle_t *, nvlist_t *);
typedef struct splitflags {
/* do not split, but return the config that would be split off */
int dryrun : 1;
/* after splitting, import the pool */
int import : 1;
} splitflags_t;
/*
* Functions to manipulate pool and vdev state
*/
extern int zpool_scrub(zpool_handle_t *, pool_scrub_type_t);
extern int zpool_clear(zpool_handle_t *, const char *);
extern int zpool_scan(zpool_handle_t *, pool_scan_func_t);
extern int zpool_clear(zpool_handle_t *, const char *, nvlist_t *);
extern int zpool_vdev_online(zpool_handle_t *, const char *, int,
vdev_state_t *);
@ -224,13 +238,17 @@ extern int zpool_vdev_attach(zpool_handle_t *, const char *,
const char *, nvlist_t *, int);
extern int zpool_vdev_detach(zpool_handle_t *, const char *);
extern int zpool_vdev_remove(zpool_handle_t *, const char *);
extern int zpool_vdev_split(zpool_handle_t *, char *, nvlist_t **, nvlist_t *,
splitflags_t);
extern int zpool_vdev_fault(zpool_handle_t *, uint64_t);
extern int zpool_vdev_degrade(zpool_handle_t *, uint64_t);
extern int zpool_vdev_fault(zpool_handle_t *, uint64_t, vdev_aux_t);
extern int zpool_vdev_degrade(zpool_handle_t *, uint64_t, vdev_aux_t);
extern int zpool_vdev_clear(zpool_handle_t *, uint64_t);
extern nvlist_t *zpool_find_vdev(zpool_handle_t *, const char *, boolean_t *,
boolean_t *, boolean_t *);
extern nvlist_t *zpool_find_vdev_by_physpath(zpool_handle_t *, const char *,
boolean_t *, boolean_t *, boolean_t *);
extern int zpool_label_disk(libzfs_handle_t *, zpool_handle_t *, char *);
/*
@ -284,6 +302,7 @@ typedef enum {
ZPOOL_STATUS_VERSION_OLDER, /* older on-disk version */
ZPOOL_STATUS_RESILVERING, /* device being resilvered */
ZPOOL_STATUS_OFFLINE_DEV, /* device online */
ZPOOL_STATUS_REMOVED_DEV, /* removed device */
/*
* Finally, the following indicates a healthy pool.
@ -293,6 +312,7 @@ typedef enum {
extern zpool_status_t zpool_get_status(zpool_handle_t *, char **);
extern zpool_status_t zpool_import_status(nvlist_t *, char **);
extern void zpool_dump_ddt(const ddt_stat_t *dds, const ddt_histogram_t *ddh);
/*
* Statistics and configuration functions.
@ -309,35 +329,53 @@ extern int zpool_export_force(zpool_handle_t *);
extern int zpool_import(libzfs_handle_t *, nvlist_t *, const char *,
char *altroot);
extern int zpool_import_props(libzfs_handle_t *, nvlist_t *, const char *,
nvlist_t *, boolean_t);
nvlist_t *, int);
/*
* Search for pools to import
*/
typedef struct importargs {
char **path; /* a list of paths to search */
int paths; /* number of paths to search */
char *poolname; /* name of a pool to find */
uint64_t guid; /* guid of a pool to find */
char *cachefile; /* cachefile to use for import */
int can_be_active : 1; /* can the pool be active? */
int unique : 1; /* does 'poolname' already exist? */
int exists : 1; /* set on return if pool already exists */
} importargs_t;
extern nvlist_t *zpool_search_import(libzfs_handle_t *, importargs_t *);
/* legacy pool search routines */
extern nvlist_t *zpool_find_import(libzfs_handle_t *, int, char **);
extern nvlist_t *zpool_find_import_cached(libzfs_handle_t *, const char *,
char *, uint64_t);
extern nvlist_t *zpool_find_import_byname(libzfs_handle_t *, int, char **,
char *);
extern nvlist_t *zpool_find_import_byguid(libzfs_handle_t *, int, char **,
uint64_t);
extern nvlist_t *zpool_find_import_activeok(libzfs_handle_t *, int, char **);
/*
* Miscellaneous pool functions
*/
struct zfs_cmd;
extern char *zpool_vdev_name(libzfs_handle_t *, zpool_handle_t *, nvlist_t *);
extern const char *zfs_history_event_names[LOG_END];
extern char *zpool_vdev_name(libzfs_handle_t *, zpool_handle_t *, nvlist_t *,
boolean_t verbose);
extern int zpool_upgrade(zpool_handle_t *, uint64_t);
extern int zpool_get_history(zpool_handle_t *, nvlist_t **);
extern int zpool_history_unpack(char *, uint64_t, uint64_t *,
nvlist_t ***, uint_t *);
extern void zpool_set_history_str(const char *subcommand, int argc,
char **argv, char *history_str);
extern int zpool_stage_history(libzfs_handle_t *, const char *);
extern void zpool_obj_to_path(zpool_handle_t *, uint64_t, uint64_t, char *,
size_t len);
extern int zfs_ioctl(libzfs_handle_t *, unsigned long, struct zfs_cmd *);
extern int zpool_get_physpath(zpool_handle_t *, char *);
extern int zpool_get_physpath(zpool_handle_t *, char *, size_t);
extern void zpool_explain_recover(libzfs_handle_t *, const char *, int,
nvlist_t *);
/*
* Basic handle manipulations. These functions do not create or destroy the
* underlying datasets, only the references to them.
@ -368,6 +406,8 @@ extern const char *zfs_prop_to_name(zfs_prop_t);
extern int zfs_prop_set(zfs_handle_t *, const char *, const char *);
extern int zfs_prop_get(zfs_handle_t *, zfs_prop_t, char *, size_t,
zprop_source_t *, char *, size_t, boolean_t);
extern int zfs_prop_get_recvd(zfs_handle_t *, const char *, char *, size_t,
boolean_t);
extern int zfs_prop_get_numeric(zfs_handle_t *, zfs_prop_t, uint64_t *,
zprop_source_t *, char *, size_t);
extern int zfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname,
@ -375,10 +415,11 @@ extern int zfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname,
extern int zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname,
char *propbuf, int proplen, boolean_t literal);
extern uint64_t zfs_prop_get_int(zfs_handle_t *, zfs_prop_t);
extern int zfs_prop_inherit(zfs_handle_t *, const char *);
extern int zfs_prop_inherit(zfs_handle_t *, const char *, boolean_t);
extern const char *zfs_prop_values(zfs_prop_t);
extern int zfs_prop_is_string(zfs_prop_t prop);
extern nvlist_t *zfs_get_user_props(zfs_handle_t *);
extern nvlist_t *zfs_get_recvd_props(zfs_handle_t *);
typedef struct zprop_list {
int pl_prop;
@ -386,10 +427,11 @@ typedef struct zprop_list {
struct zprop_list *pl_next;
boolean_t pl_all;
size_t pl_width;
size_t pl_recvd_width;
boolean_t pl_fixed;
} zprop_list_t;
extern int zfs_expand_proplist(zfs_handle_t *, zprop_list_t **);
extern int zfs_expand_proplist(zfs_handle_t *, zprop_list_t **, boolean_t);
extern void zfs_prune_proplist(zfs_handle_t *, uint8_t *);
#define ZFS_MOUNTPOINT_NONE "none"
@ -413,13 +455,24 @@ extern int zprop_get_list(libzfs_handle_t *, char *, zprop_list_t **,
zfs_type_t);
extern void zprop_free_list(zprop_list_t *);
#define ZFS_GET_NCOLS 5
typedef enum {
GET_COL_NONE,
GET_COL_NAME,
GET_COL_PROPERTY,
GET_COL_VALUE,
GET_COL_RECVD,
GET_COL_SOURCE
} zfs_get_column_t;
/*
* Functions for printing zfs or zpool properties
*/
typedef struct zprop_get_cbdata {
int cb_sources;
int cb_columns[4];
int cb_colwidths[5];
zfs_get_column_t cb_columns[ZFS_GET_NCOLS];
int cb_colwidths[ZFS_GET_NCOLS + 1];
boolean_t cb_scripted;
boolean_t cb_literal;
boolean_t cb_first;
@ -428,12 +481,8 @@ typedef struct zprop_get_cbdata {
} zprop_get_cbdata_t;
void zprop_print_one_property(const char *, zprop_get_cbdata_t *,
const char *, const char *, zprop_source_t, const char *);
#define GET_COL_NAME 1
#define GET_COL_PROPERTY 2
#define GET_COL_VALUE 3
#define GET_COL_SOURCE 4
const char *, const char *, zprop_source_t, const char *,
const char *);
/*
* Iterator functions.
@ -444,6 +493,18 @@ extern int zfs_iter_children(zfs_handle_t *, zfs_iter_f, void *);
extern int zfs_iter_dependents(zfs_handle_t *, boolean_t, zfs_iter_f, void *);
extern int zfs_iter_filesystems(zfs_handle_t *, zfs_iter_f, void *);
extern int zfs_iter_snapshots(zfs_handle_t *, zfs_iter_f, void *);
extern int zfs_iter_snapshots_sorted(zfs_handle_t *, zfs_iter_f, void *);
typedef struct get_all_cb {
zfs_handle_t **cb_handles;
size_t cb_alloc;
size_t cb_used;
boolean_t cb_verbose;
int (*cb_getone)(zfs_handle_t *, void *);
} get_all_cb_t;
void libzfs_add_handle(get_all_cb_t *, zfs_handle_t *);
int libzfs_dataset_cmp(const void *, const void *);
/*
* Functions to create and destroy datasets.
@ -451,21 +512,54 @@ extern int zfs_iter_snapshots(zfs_handle_t *, zfs_iter_f, void *);
extern int zfs_create(libzfs_handle_t *, const char *, zfs_type_t,
nvlist_t *);
extern int zfs_create_ancestors(libzfs_handle_t *, const char *);
extern int zfs_destroy(zfs_handle_t *);
extern int zfs_destroy_snaps(zfs_handle_t *, char *);
extern int zfs_destroy(zfs_handle_t *, boolean_t);
extern int zfs_destroy_snaps(zfs_handle_t *, char *, boolean_t);
extern int zfs_clone(zfs_handle_t *, const char *, nvlist_t *);
extern int zfs_snapshot(libzfs_handle_t *, const char *, boolean_t, nvlist_t *);
extern int zfs_rollback(zfs_handle_t *, zfs_handle_t *, boolean_t);
extern int zfs_rename(zfs_handle_t *, const char *, boolean_t);
extern int zfs_send(zfs_handle_t *, const char *, const char *,
boolean_t, boolean_t, boolean_t, boolean_t, int);
typedef struct sendflags {
/* print informational messages (ie, -v was specified) */
int verbose : 1;
/* recursive send (ie, -R) */
int replicate : 1;
/* for incrementals, do all intermediate snapshots */
int doall : 1; /* (ie, -I) */
/* if dataset is a clone, do incremental from its origin */
int fromorigin : 1;
/* do deduplication */
int dedup : 1;
/* send properties (ie, -p) */
int props : 1;
} sendflags_t;
typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *);
extern int zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
sendflags_t flags, int outfd, snapfilter_cb_t filter_func,
void *cb_arg, nvlist_t **debugnvp);
extern int zfs_promote(zfs_handle_t *);
extern int zfs_hold(zfs_handle_t *, const char *, const char *, boolean_t,
boolean_t, boolean_t, int, uint64_t, uint64_t);
extern int zfs_release(zfs_handle_t *, const char *, const char *, boolean_t);
extern int zfs_get_holds(zfs_handle_t *, nvlist_t **);
extern uint64_t zvol_volsize_to_reservation(uint64_t, nvlist_t *);
typedef int (*zfs_userspace_cb_t)(void *arg, const char *domain,
uid_t rid, uint64_t space);
extern int zfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type,
zfs_userspace_cb_t func, void *arg);
extern int zfs_userspace(zfs_handle_t *, zfs_userquota_prop_t,
zfs_userspace_cb_t, void *);
extern int zfs_get_fsacl(zfs_handle_t *, nvlist_t **);
extern int zfs_set_fsacl(zfs_handle_t *, boolean_t, nvlist_t *);
typedef struct recvflags {
/* print informational messages (ie, -v was specified) */
@ -474,6 +568,12 @@ typedef struct recvflags {
/* the destination is a prefix, not the exact fs (ie, -d) */
int isprefix : 1;
/*
* Only the tail of the sent snapshot path is appended to the
* destination to determine the received snapshot name (ie, -e).
*/
int istail : 1;
/* do not actually do the recv, just check if it would work (ie, -n) */
int dryrun : 1;
@ -493,6 +593,15 @@ typedef struct recvflags {
extern int zfs_receive(libzfs_handle_t *, const char *, recvflags_t,
int, avl_tree_t *);
typedef enum diff_flags {
ZFS_DIFF_PARSEABLE = 0x1,
ZFS_DIFF_TIMESTAMP = 0x2,
ZFS_DIFF_CLASSIFY = 0x4
} diff_flags_t;
extern int zfs_show_diffs(zfs_handle_t *, int, const char *, const char *,
int);
/*
* Miscellaneous functions.
*/
@ -534,12 +643,6 @@ extern int zfs_unshareall_nfs(zfs_handle_t *);
extern int zfs_unshareall_smb(zfs_handle_t *);
extern int zfs_unshareall_bypath(zfs_handle_t *, const char *);
extern int zfs_unshareall(zfs_handle_t *);
extern boolean_t zfs_is_shared_iscsi(zfs_handle_t *);
extern int zfs_share_iscsi(zfs_handle_t *);
extern int zfs_unshare_iscsi(zfs_handle_t *);
#ifdef TODO
extern int zfs_iscsi_perm_check(libzfs_handle_t *, char *, ucred_t *);
#endif
extern int zfs_deleg_share_nfs(libzfs_handle_t *, char *, char *, char *,
void *, void *, int, zfs_share_op_t);
@ -572,15 +675,10 @@ extern int zpool_in_use(libzfs_handle_t *, int, pool_state_t *, char **,
boolean_t *);
/*
* ftyp special. Read the label from a given device.
* Label manipulation.
*/
extern int zpool_read_label(int, nvlist_t **);
/*
* Create and remove zvol /dev links.
*/
extern int zpool_create_zvol_links(zpool_handle_t *);
extern int zpool_remove_zvol_links(zpool_handle_t *);
extern int zpool_clear_label(int);
/* is this zvol valid for use as a dump device? */
extern int zvol_check_dump_config(char *);
@ -601,10 +699,21 @@ int zfs_smb_acl_rename(libzfs_handle_t *, char *, char *, char *, char *);
extern int zpool_enable_datasets(zpool_handle_t *, const char *, int);
extern int zpool_disable_datasets(zpool_handle_t *, boolean_t);
#ifdef __FreeBSD__
/*
* Mappings between vdev and FRU.
*/
extern void libzfs_fru_refresh(libzfs_handle_t *);
extern const char *libzfs_fru_lookup(libzfs_handle_t *, const char *);
extern const char *libzfs_fru_devpath(libzfs_handle_t *, const char *);
extern boolean_t libzfs_fru_compare(libzfs_handle_t *, const char *,
const char *);
extern boolean_t libzfs_fru_notself(libzfs_handle_t *, const char *);
extern int zpool_fru_set(zpool_handle_t *, uint64_t, const char *);
#ifndef sun
extern int zmount(const char *, const char *, int, char *, char *, int, char *,
int);
#endif
#endif /* !sun */
#ifdef __cplusplus
}

View File

@ -20,7 +20,7 @@
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Portions Copyright 2007 Ramprakash Jelari
@ -116,32 +116,7 @@ changelist_prefix(prop_changelist_t *clp)
if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
continue;
if (ZFS_IS_VOLUME(cn->cn_handle)) {
switch (clp->cl_realprop) {
case ZFS_PROP_NAME:
/*
* If this was a rename, unshare the zvol, and
* remove the /dev/zvol links.
*/
(void) zfs_unshare_iscsi(cn->cn_handle);
if (zvol_remove_link(cn->cn_handle->zfs_hdl,
cn->cn_handle->zfs_name) != 0) {
ret = -1;
cn->cn_needpost = B_FALSE;
(void) zfs_share_iscsi(cn->cn_handle);
}
break;
case ZFS_PROP_VOLSIZE:
/*
* If this was a change to the volume size, we
* need to unshare and reshare the volume.
*/
(void) zfs_unshare_iscsi(cn->cn_handle);
break;
}
} else {
if (!ZFS_IS_VOLUME(cn->cn_handle)) {
/*
* Do the property specific processing.
*/
@ -234,32 +209,8 @@ changelist_postfix(prop_changelist_t *clp)
zfs_refresh_properties(cn->cn_handle);
if (ZFS_IS_VOLUME(cn->cn_handle)) {
/*
* If we're doing a rename, recreate the /dev/zvol
* links.
*/
if (clp->cl_realprop == ZFS_PROP_NAME &&
zvol_create_link(cn->cn_handle->zfs_hdl,
cn->cn_handle->zfs_name) != 0) {
errors++;
} else if (cn->cn_shared ||
clp->cl_prop == ZFS_PROP_SHAREISCSI) {
if (zfs_prop_get(cn->cn_handle,
ZFS_PROP_SHAREISCSI, shareopts,
sizeof (shareopts), NULL, NULL, 0,
B_FALSE) == 0 &&
strcmp(shareopts, "off") == 0) {
errors +=
zfs_unshare_iscsi(cn->cn_handle);
} else {
errors +=
zfs_share_iscsi(cn->cn_handle);
}
}
if (ZFS_IS_VOLUME(cn->cn_handle))
continue;
}
/*
* Remount if previously mounted or mountpoint was legacy,
@ -508,6 +459,14 @@ change_one(zfs_handle_t *zhp, void *data)
&idx);
uu_list_insert(clp->cl_list, cn, idx);
} else {
/*
* Add this child to beginning of the list. Children
* below this one in the hierarchy will get added above
* this one in the list. This produces a list in
* reverse dataset name order.
* This is necessary when the original mountpoint
* is legacy or none.
*/
ASSERT(!clp->cl_alldependents);
verify(uu_list_insert_before(clp->cl_list,
uu_list_first(clp->cl_list), cn) == 0);
@ -574,6 +533,7 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int gather_flags,
zfs_handle_t *temp;
char property[ZFS_MAXPROPLEN];
uu_compare_fn_t *compare = NULL;
boolean_t legacy = B_FALSE;
if ((clp = zfs_alloc(zhp->zfs_hdl, sizeof (prop_changelist_t))) == NULL)
return (NULL);
@ -586,8 +546,19 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int gather_flags,
if (prop == ZFS_PROP_NAME || prop == ZFS_PROP_ZONED ||
prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS ||
prop == ZFS_PROP_SHARESMB) {
compare = compare_mountpoints;
clp->cl_sorted = B_TRUE;
if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT,
property, sizeof (property),
NULL, NULL, 0, B_FALSE) == 0 &&
(strcmp(property, "legacy") == 0 ||
strcmp(property, "none") == 0)) {
legacy = B_TRUE;
}
if (!legacy) {
compare = compare_mountpoints;
clp->cl_sorted = B_TRUE;
}
}
clp->cl_pool = uu_list_pool_create("changelist_pool",
@ -638,8 +609,7 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int gather_flags,
if (clp->cl_prop != ZFS_PROP_MOUNTPOINT &&
clp->cl_prop != ZFS_PROP_SHARENFS &&
clp->cl_prop != ZFS_PROP_SHARESMB &&
clp->cl_prop != ZFS_PROP_SHAREISCSI)
clp->cl_prop != ZFS_PROP_SHARESMB)
return (clp);
/*
@ -695,6 +665,12 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int gather_flags,
(void) uu_list_find(clp->cl_list, cn, NULL, &idx);
uu_list_insert(clp->cl_list, cn, idx);
} else {
/*
* Add the target dataset to the end of the list.
* The list is not really unsorted. The list will be
* in reverse dataset name order. This is necessary
* when the original mountpoint is legacy or none.
*/
verify(uu_list_insert_after(clp->cl_list,
uu_list_last(clp->cl_list), cn) == 0);
}
@ -703,11 +679,7 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int gather_flags,
* If the mountpoint property was previously 'legacy', or 'none',
* record it as the behavior of changelist_postfix() will be different.
*/
if ((clp->cl_prop == ZFS_PROP_MOUNTPOINT) &&
(zfs_prop_get(zhp, prop, property, sizeof (property),
NULL, NULL, 0, B_FALSE) == 0 &&
(strcmp(property, "legacy") == 0 ||
strcmp(property, "none") == 0))) {
if ((clp->cl_prop == ZFS_PROP_MOUNTPOINT) && legacy) {
/*
* do not automatically mount ex-legacy datasets if
* we specifically set canmount to noauto

View File

@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* The pool configuration repository is stored in /etc/zfs/zpool.cache as a
* single packed nvlist. While it would be nice to just read in this
@ -313,21 +311,33 @@ zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data)
zpool_handle_t *zhp;
int ret;
if (namespace_reload(hdl) != 0)
/*
* If someone makes a recursive call to zpool_iter(), we want to avoid
* refreshing the namespace because that will invalidate the parent
* context. We allow recursive calls, but simply re-use the same
* namespace AVL tree.
*/
if (!hdl->libzfs_pool_iter && namespace_reload(hdl) != 0)
return (-1);
hdl->libzfs_pool_iter++;
for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0)
if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0) {
hdl->libzfs_pool_iter--;
return (-1);
}
if (zhp == NULL)
continue;
if ((ret = func(zhp, data)) != 0)
if ((ret = func(zhp, data)) != 0) {
hdl->libzfs_pool_iter--;
return (ret);
}
}
hdl->libzfs_pool_iter--;
return (0);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,832 @@
/*
* CDDL HEADER START
*
* 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]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
* zfs diff support
*/
#include <ctype.h>
#include <errno.h>
#include <libintl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stddef.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/zfs_ioctl.h>
#include <libzfs.h>
#include "libzfs_impl.h"
#define ZDIFF_SNAPDIR "/.zfs/snapshot/"
#define ZDIFF_SHARESDIR "/.zfs/shares/"
#define ZDIFF_PREFIX "zfs-diff-%d"
#define ZDIFF_ADDED '+'
#define ZDIFF_MODIFIED 'M'
#define ZDIFF_REMOVED '-'
#define ZDIFF_RENAMED 'R'
static boolean_t
do_name_cmp(const char *fpath, const char *tpath)
{
char *fname, *tname;
fname = strrchr(fpath, '/') + 1;
tname = strrchr(tpath, '/') + 1;
return (strcmp(fname, tname) == 0);
}
typedef struct differ_info {
zfs_handle_t *zhp;
char *fromsnap;
char *frommnt;
char *tosnap;
char *tomnt;
char *ds;
char *dsmnt;
char *tmpsnap;
char errbuf[1024];
boolean_t isclone;
boolean_t scripted;
boolean_t classify;
boolean_t timestamped;
uint64_t shares;
int zerr;
int cleanupfd;
int outputfd;
int datafd;
} differ_info_t;
/*
* Given a {dsname, object id}, get the object path
*/
static int
get_stats_for_obj(differ_info_t *di, const char *dsname, uint64_t obj,
char *pn, int maxlen, zfs_stat_t *sb)
{
zfs_cmd_t zc = { 0 };
int error;
(void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name));
zc.zc_obj = obj;
errno = 0;
error = ioctl(di->zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_STATS, &zc);
di->zerr = errno;
/* we can get stats even if we failed to get a path */
(void) memcpy(sb, &zc.zc_stat, sizeof (zfs_stat_t));
if (error == 0) {
ASSERT(di->zerr == 0);
(void) strlcpy(pn, zc.zc_value, maxlen);
return (0);
}
if (di->zerr == EPERM) {
(void) snprintf(di->errbuf, sizeof (di->errbuf),
dgettext(TEXT_DOMAIN,
"The sys_config privilege or diff delegated permission "
"is needed\nto discover path names"));
return (-1);
} else {
(void) snprintf(di->errbuf, sizeof (di->errbuf),
dgettext(TEXT_DOMAIN,
"Unable to determine path or stats for "
"object %lld in %s"), obj, dsname);
return (-1);
}
}
/*
* stream_bytes
*
* Prints a file name out a character at a time. If the character is
* not in the range of what we consider "printable" ASCII, display it
* as an escaped 3-digit octal value. ASCII values less than a space
* are all control characters and we declare the upper end as the
* DELete character. This also is the last 7-bit ASCII character.
* We choose to treat all 8-bit ASCII as not printable for this
* application.
*/
static void
stream_bytes(FILE *fp, const char *string)
{
while (*string) {
if (*string > ' ' && *string != '\\' && *string < '\177')
(void) fprintf(fp, "%c", *string++);
else
(void) fprintf(fp, "\\%03o", *string++);
}
}
static void
print_what(FILE *fp, mode_t what)
{
char symbol;
switch (what & S_IFMT) {
case S_IFBLK:
symbol = 'B';
break;
case S_IFCHR:
symbol = 'C';
break;
case S_IFDIR:
symbol = '/';
break;
#ifdef S_IFDOOR
case S_IFDOOR:
symbol = '>';
break;
#endif
case S_IFIFO:
symbol = '|';
break;
case S_IFLNK:
symbol = '@';
break;
#ifdef S_IFPORT
case S_IFPORT:
symbol = 'P';
break;
#endif
case S_IFSOCK:
symbol = '=';
break;
case S_IFREG:
symbol = 'F';
break;
default:
symbol = '?';
break;
}
(void) fprintf(fp, "%c", symbol);
}
static void
print_cmn(FILE *fp, differ_info_t *di, const char *file)
{
stream_bytes(fp, di->dsmnt);
stream_bytes(fp, file);
}
static void
print_rename(FILE *fp, differ_info_t *di, const char *old, const char *new,
zfs_stat_t *isb)
{
if (di->timestamped)
(void) fprintf(fp, "%10lld.%09lld\t",
(longlong_t)isb->zs_ctime[0],
(longlong_t)isb->zs_ctime[1]);
(void) fprintf(fp, "%c\t", ZDIFF_RENAMED);
if (di->classify) {
print_what(fp, isb->zs_mode);
(void) fprintf(fp, "\t");
}
print_cmn(fp, di, old);
if (di->scripted)
(void) fprintf(fp, "\t");
else
(void) fprintf(fp, " -> ");
print_cmn(fp, di, new);
(void) fprintf(fp, "\n");
}
static void
print_link_change(FILE *fp, differ_info_t *di, int delta, const char *file,
zfs_stat_t *isb)
{
if (di->timestamped)
(void) fprintf(fp, "%10lld.%09lld\t",
(longlong_t)isb->zs_ctime[0],
(longlong_t)isb->zs_ctime[1]);
(void) fprintf(fp, "%c\t", ZDIFF_MODIFIED);
if (di->classify) {
print_what(fp, isb->zs_mode);
(void) fprintf(fp, "\t");
}
print_cmn(fp, di, file);
(void) fprintf(fp, "\t(%+d)", delta);
(void) fprintf(fp, "\n");
}
static void
print_file(FILE *fp, differ_info_t *di, char type, const char *file,
zfs_stat_t *isb)
{
if (di->timestamped)
(void) fprintf(fp, "%10lld.%09lld\t",
(longlong_t)isb->zs_ctime[0],
(longlong_t)isb->zs_ctime[1]);
(void) fprintf(fp, "%c\t", type);
if (di->classify) {
print_what(fp, isb->zs_mode);
(void) fprintf(fp, "\t");
}
print_cmn(fp, di, file);
(void) fprintf(fp, "\n");
}
static int
write_inuse_diffs_one(FILE *fp, differ_info_t *di, uint64_t dobj)
{
struct zfs_stat fsb, tsb;
boolean_t same_name;
mode_t fmode, tmode;
char fobjname[MAXPATHLEN], tobjname[MAXPATHLEN];
int fobjerr, tobjerr;
int change;
if (dobj == di->shares)
return (0);
/*
* Check the from and to snapshots for info on the object. If
* we get ENOENT, then the object just didn't exist in that
* snapshot. If we get ENOTSUP, then we tried to get
* info on a non-ZPL object, which we don't care about anyway.
*/
fobjerr = get_stats_for_obj(di, di->fromsnap, dobj, fobjname,
MAXPATHLEN, &fsb);
if (fobjerr && di->zerr != ENOENT && di->zerr != ENOTSUP)
return (-1);
tobjerr = get_stats_for_obj(di, di->tosnap, dobj, tobjname,
MAXPATHLEN, &tsb);
if (tobjerr && di->zerr != ENOENT && di->zerr != ENOTSUP)
return (-1);
/*
* Unallocated object sharing the same meta dnode block
*/
if (fobjerr && tobjerr) {
ASSERT(di->zerr == ENOENT || di->zerr == ENOTSUP);
di->zerr = 0;
return (0);
}
di->zerr = 0; /* negate get_stats_for_obj() from side that failed */
fmode = fsb.zs_mode & S_IFMT;
tmode = tsb.zs_mode & S_IFMT;
if (fmode == S_IFDIR || tmode == S_IFDIR || fsb.zs_links == 0 ||
tsb.zs_links == 0)
change = 0;
else
change = tsb.zs_links - fsb.zs_links;
if (fobjerr) {
if (change) {
print_link_change(fp, di, change, tobjname, &tsb);
return (0);
}
print_file(fp, di, ZDIFF_ADDED, tobjname, &tsb);
return (0);
} else if (tobjerr) {
if (change) {
print_link_change(fp, di, change, fobjname, &fsb);
return (0);
}
print_file(fp, di, ZDIFF_REMOVED, fobjname, &fsb);
return (0);
}
if (fmode != tmode && fsb.zs_gen == tsb.zs_gen)
tsb.zs_gen++; /* Force a generational difference */
same_name = do_name_cmp(fobjname, tobjname);
/* Simple modification or no change */
if (fsb.zs_gen == tsb.zs_gen) {
/* No apparent changes. Could we assert !this? */
if (fsb.zs_ctime[0] == tsb.zs_ctime[0] &&
fsb.zs_ctime[1] == tsb.zs_ctime[1])
return (0);
if (change) {
print_link_change(fp, di, change,
change > 0 ? fobjname : tobjname, &tsb);
} else if (same_name) {
print_file(fp, di, ZDIFF_MODIFIED, fobjname, &tsb);
} else {
print_rename(fp, di, fobjname, tobjname, &tsb);
}
return (0);
} else {
/* file re-created or object re-used */
print_file(fp, di, ZDIFF_REMOVED, fobjname, &fsb);
print_file(fp, di, ZDIFF_ADDED, tobjname, &tsb);
return (0);
}
}
static int
write_inuse_diffs(FILE *fp, differ_info_t *di, dmu_diff_record_t *dr)
{
uint64_t o;
int err;
for (o = dr->ddr_first; o <= dr->ddr_last; o++) {
if (err = write_inuse_diffs_one(fp, di, o))
return (err);
}
return (0);
}
static int
describe_free(FILE *fp, differ_info_t *di, uint64_t object, char *namebuf,
int maxlen)
{
struct zfs_stat sb;
if (get_stats_for_obj(di, di->fromsnap, object, namebuf,
maxlen, &sb) != 0) {
/* Let it slide, if in the delete queue on from side */
if (di->zerr == ENOENT && sb.zs_links == 0) {
di->zerr = 0;
return (0);
}
return (-1);
}
print_file(fp, di, ZDIFF_REMOVED, namebuf, &sb);
return (0);
}
static int
write_free_diffs(FILE *fp, differ_info_t *di, dmu_diff_record_t *dr)
{
zfs_cmd_t zc = { 0 };
libzfs_handle_t *lhdl = di->zhp->zfs_hdl;
char fobjname[MAXPATHLEN];
(void) strlcpy(zc.zc_name, di->fromsnap, sizeof (zc.zc_name));
zc.zc_obj = dr->ddr_first - 1;
ASSERT(di->zerr == 0);
while (zc.zc_obj < dr->ddr_last) {
int err;
err = ioctl(lhdl->libzfs_fd, ZFS_IOC_NEXT_OBJ, &zc);
if (err == 0) {
if (zc.zc_obj == di->shares) {
zc.zc_obj++;
continue;
}
if (zc.zc_obj > dr->ddr_last) {
break;
}
err = describe_free(fp, di, zc.zc_obj, fobjname,
MAXPATHLEN);
if (err)
break;
} else if (errno == ESRCH) {
break;
} else {
(void) snprintf(di->errbuf, sizeof (di->errbuf),
dgettext(TEXT_DOMAIN,
"next allocated object (> %lld) find failure"),
zc.zc_obj);
di->zerr = errno;
break;
}
}
if (di->zerr)
return (-1);
return (0);
}
static void *
differ(void *arg)
{
differ_info_t *di = arg;
dmu_diff_record_t dr;
FILE *ofp;
int err = 0;
if ((ofp = fdopen(di->outputfd, "w")) == NULL) {
di->zerr = errno;
(void) strerror_r(errno, di->errbuf, sizeof (di->errbuf));
(void) close(di->datafd);
return ((void *)-1);
}
for (;;) {
char *cp = (char *)&dr;
int len = sizeof (dr);
int rv;
do {
rv = read(di->datafd, cp, len);
cp += rv;
len -= rv;
} while (len > 0 && rv > 0);
if (rv < 0 || (rv == 0 && len != sizeof (dr))) {
di->zerr = EPIPE;
break;
} else if (rv == 0) {
/* end of file at a natural breaking point */
break;
}
switch (dr.ddr_type) {
case DDR_FREE:
err = write_free_diffs(ofp, di, &dr);
break;
case DDR_INUSE:
err = write_inuse_diffs(ofp, di, &dr);
break;
default:
di->zerr = EPIPE;
break;
}
if (err || di->zerr)
break;
}
(void) fclose(ofp);
(void) close(di->datafd);
if (err)
return ((void *)-1);
if (di->zerr) {
ASSERT(di->zerr == EINVAL);
(void) snprintf(di->errbuf, sizeof (di->errbuf),
dgettext(TEXT_DOMAIN,
"Internal error: bad data from diff IOCTL"));
return ((void *)-1);
}
return ((void *)0);
}
static int
find_shares_object(differ_info_t *di)
{
char fullpath[MAXPATHLEN];
struct stat64 sb = { 0 };
(void) strlcpy(fullpath, di->dsmnt, MAXPATHLEN);
(void) strlcat(fullpath, ZDIFF_SHARESDIR, MAXPATHLEN);
if (stat64(fullpath, &sb) != 0) {
#ifdef sun
(void) snprintf(di->errbuf, sizeof (di->errbuf),
dgettext(TEXT_DOMAIN, "Cannot stat %s"), fullpath);
return (zfs_error(di->zhp->zfs_hdl, EZFS_DIFF, di->errbuf));
#else
return (0);
#endif
}
di->shares = (uint64_t)sb.st_ino;
return (0);
}
static int
make_temp_snapshot(differ_info_t *di)
{
libzfs_handle_t *hdl = di->zhp->zfs_hdl;
zfs_cmd_t zc = { 0 };
(void) snprintf(zc.zc_value, sizeof (zc.zc_value),
ZDIFF_PREFIX, getpid());
(void) strlcpy(zc.zc_name, di->ds, sizeof (zc.zc_name));
zc.zc_cleanup_fd = di->cleanupfd;
if (ioctl(hdl->libzfs_fd, ZFS_IOC_TMP_SNAPSHOT, &zc) != 0) {
int err = errno;
if (err == EPERM) {
(void) snprintf(di->errbuf, sizeof (di->errbuf),
dgettext(TEXT_DOMAIN, "The diff delegated "
"permission is needed in order\nto create a "
"just-in-time snapshot for diffing\n"));
return (zfs_error(hdl, EZFS_DIFF, di->errbuf));
} else {
(void) snprintf(di->errbuf, sizeof (di->errbuf),
dgettext(TEXT_DOMAIN, "Cannot create just-in-time "
"snapshot of '%s'"), zc.zc_name);
return (zfs_standard_error(hdl, err, di->errbuf));
}
}
di->tmpsnap = zfs_strdup(hdl, zc.zc_value);
di->tosnap = zfs_asprintf(hdl, "%s@%s", di->ds, di->tmpsnap);
return (0);
}
static void
teardown_differ_info(differ_info_t *di)
{
free(di->ds);
free(di->dsmnt);
free(di->fromsnap);
free(di->frommnt);
free(di->tosnap);
free(di->tmpsnap);
free(di->tomnt);
(void) close(di->cleanupfd);
}
static int
get_snapshot_names(differ_info_t *di, const char *fromsnap,
const char *tosnap)
{
libzfs_handle_t *hdl = di->zhp->zfs_hdl;
char *atptrf = NULL;
char *atptrt = NULL;
int fdslen, fsnlen;
int tdslen, tsnlen;
/*
* Can accept
* dataset@snap1
* dataset@snap1 dataset@snap2
* dataset@snap1 @snap2
* dataset@snap1 dataset
* @snap1 dataset@snap2
*/
if (tosnap == NULL) {
/* only a from snapshot given, must be valid */
(void) snprintf(di->errbuf, sizeof (di->errbuf),
dgettext(TEXT_DOMAIN,
"Badly formed snapshot name %s"), fromsnap);
if (!zfs_validate_name(hdl, fromsnap, ZFS_TYPE_SNAPSHOT,
B_FALSE)) {
return (zfs_error(hdl, EZFS_INVALIDNAME,
di->errbuf));
}
atptrf = strchr(fromsnap, '@');
ASSERT(atptrf != NULL);
fdslen = atptrf - fromsnap;
di->fromsnap = zfs_strdup(hdl, fromsnap);
di->ds = zfs_strdup(hdl, fromsnap);
di->ds[fdslen] = '\0';
/* the to snap will be a just-in-time snap of the head */
return (make_temp_snapshot(di));
}
(void) snprintf(di->errbuf, sizeof (di->errbuf),
dgettext(TEXT_DOMAIN,
"Unable to determine which snapshots to compare"));
atptrf = strchr(fromsnap, '@');
atptrt = strchr(tosnap, '@');
fdslen = atptrf ? atptrf - fromsnap : strlen(fromsnap);
tdslen = atptrt ? atptrt - tosnap : strlen(tosnap);
fsnlen = strlen(fromsnap) - fdslen; /* includes @ sign */
tsnlen = strlen(tosnap) - tdslen; /* includes @ sign */
if (fsnlen <= 1 || tsnlen == 1 || (fdslen == 0 && tdslen == 0) ||
(fsnlen == 0 && tsnlen == 0)) {
return (zfs_error(hdl, EZFS_INVALIDNAME, di->errbuf));
} else if ((fdslen > 0 && tdslen > 0) &&
((tdslen != fdslen || strncmp(fromsnap, tosnap, fdslen) != 0))) {
/*
* not the same dataset name, might be okay if
* tosnap is a clone of a fromsnap descendant.
*/
char origin[ZFS_MAXNAMELEN];
zprop_source_t src;
zfs_handle_t *zhp;
di->ds = zfs_alloc(di->zhp->zfs_hdl, tdslen + 1);
(void) strncpy(di->ds, tosnap, tdslen);
di->ds[tdslen] = '\0';
zhp = zfs_open(hdl, di->ds, ZFS_TYPE_FILESYSTEM);
while (zhp != NULL) {
(void) zfs_prop_get(zhp, ZFS_PROP_ORIGIN,
origin, sizeof (origin), &src, NULL, 0, B_FALSE);
if (strncmp(origin, fromsnap, fsnlen) == 0)
break;
(void) zfs_close(zhp);
zhp = zfs_open(hdl, origin, ZFS_TYPE_FILESYSTEM);
}
if (zhp == NULL) {
(void) snprintf(di->errbuf, sizeof (di->errbuf),
dgettext(TEXT_DOMAIN,
"Not an earlier snapshot from the same fs"));
return (zfs_error(hdl, EZFS_INVALIDNAME, di->errbuf));
} else {
(void) zfs_close(zhp);
}
di->isclone = B_TRUE;
di->fromsnap = zfs_strdup(hdl, fromsnap);
if (tsnlen) {
di->tosnap = zfs_strdup(hdl, tosnap);
} else {
return (make_temp_snapshot(di));
}
} else {
int dslen = fdslen ? fdslen : tdslen;
di->ds = zfs_alloc(hdl, dslen + 1);
(void) strncpy(di->ds, fdslen ? fromsnap : tosnap, dslen);
di->ds[dslen] = '\0';
di->fromsnap = zfs_asprintf(hdl, "%s%s", di->ds, atptrf);
if (tsnlen) {
di->tosnap = zfs_asprintf(hdl, "%s%s", di->ds, atptrt);
} else {
return (make_temp_snapshot(di));
}
}
return (0);
}
static int
get_mountpoint(differ_info_t *di, char *dsnm, char **mntpt)
{
boolean_t mounted;
mounted = is_mounted(di->zhp->zfs_hdl, dsnm, mntpt);
if (mounted == B_FALSE) {
(void) snprintf(di->errbuf, sizeof (di->errbuf),
dgettext(TEXT_DOMAIN,
"Cannot diff an unmounted snapshot"));
return (zfs_error(di->zhp->zfs_hdl, EZFS_BADTYPE, di->errbuf));
}
/* Avoid a double slash at the beginning of root-mounted datasets */
if (**mntpt == '/' && *(*mntpt + 1) == '\0')
**mntpt = '\0';
return (0);
}
static int
get_mountpoints(differ_info_t *di)
{
char *strptr;
char *frommntpt;
/*
* first get the mountpoint for the parent dataset
*/
if (get_mountpoint(di, di->ds, &di->dsmnt) != 0)
return (-1);
strptr = strchr(di->tosnap, '@');
ASSERT3P(strptr, !=, NULL);
di->tomnt = zfs_asprintf(di->zhp->zfs_hdl, "%s%s%s", di->dsmnt,
ZDIFF_SNAPDIR, ++strptr);
strptr = strchr(di->fromsnap, '@');
ASSERT3P(strptr, !=, NULL);
frommntpt = di->dsmnt;
if (di->isclone) {
char *mntpt;
int err;
*strptr = '\0';
err = get_mountpoint(di, di->fromsnap, &mntpt);
*strptr = '@';
if (err != 0)
return (-1);
frommntpt = mntpt;
}
di->frommnt = zfs_asprintf(di->zhp->zfs_hdl, "%s%s%s", frommntpt,
ZDIFF_SNAPDIR, ++strptr);
if (di->isclone)
free(frommntpt);
return (0);
}
static int
setup_differ_info(zfs_handle_t *zhp, const char *fromsnap,
const char *tosnap, differ_info_t *di)
{
di->zhp = zhp;
di->cleanupfd = open(ZFS_DEV, O_RDWR|O_EXCL);
VERIFY(di->cleanupfd >= 0);
if (get_snapshot_names(di, fromsnap, tosnap) != 0)
return (-1);
if (get_mountpoints(di) != 0)
return (-1);
if (find_shares_object(di) != 0)
return (-1);
return (0);
}
int
zfs_show_diffs(zfs_handle_t *zhp, int outfd, const char *fromsnap,
const char *tosnap, int flags)
{
zfs_cmd_t zc = { 0 };
char errbuf[1024];
differ_info_t di = { 0 };
pthread_t tid;
int pipefd[2];
int iocerr;
(void) snprintf(errbuf, sizeof (errbuf),
dgettext(TEXT_DOMAIN, "zfs diff failed"));
if (setup_differ_info(zhp, fromsnap, tosnap, &di)) {
teardown_differ_info(&di);
return (-1);
}
if (pipe(pipefd)) {
zfs_error_aux(zhp->zfs_hdl, strerror(errno));
teardown_differ_info(&di);
return (zfs_error(zhp->zfs_hdl, EZFS_PIPEFAILED, errbuf));
}
di.scripted = (flags & ZFS_DIFF_PARSEABLE);
di.classify = (flags & ZFS_DIFF_CLASSIFY);
di.timestamped = (flags & ZFS_DIFF_TIMESTAMP);
di.outputfd = outfd;
di.datafd = pipefd[0];
if (pthread_create(&tid, NULL, differ, &di)) {
zfs_error_aux(zhp->zfs_hdl, strerror(errno));
(void) close(pipefd[0]);
(void) close(pipefd[1]);
teardown_differ_info(&di);
return (zfs_error(zhp->zfs_hdl,
EZFS_THREADCREATEFAILED, errbuf));
}
/* do the ioctl() */
(void) strlcpy(zc.zc_value, di.fromsnap, strlen(di.fromsnap) + 1);
(void) strlcpy(zc.zc_name, di.tosnap, strlen(di.tosnap) + 1);
zc.zc_cookie = pipefd[1];
iocerr = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DIFF, &zc);
if (iocerr != 0) {
(void) snprintf(errbuf, sizeof (errbuf),
dgettext(TEXT_DOMAIN, "Unable to obtain diffs"));
if (errno == EPERM) {
zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
"\n The sys_mount privilege or diff delegated "
"permission is needed\n to execute the "
"diff ioctl"));
} else if (errno == EXDEV) {
zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
"\n Not an earlier snapshot from the same fs"));
} else if (errno != EPIPE || di.zerr == 0) {
zfs_error_aux(zhp->zfs_hdl, strerror(errno));
}
(void) close(pipefd[1]);
(void) pthread_cancel(tid);
(void) pthread_join(tid, NULL);
teardown_differ_info(&di);
if (di.zerr != 0 && di.zerr != EPIPE) {
zfs_error_aux(zhp->zfs_hdl, strerror(di.zerr));
return (zfs_error(zhp->zfs_hdl, EZFS_DIFF, di.errbuf));
} else {
return (zfs_error(zhp->zfs_hdl, EZFS_DIFFDATA, errbuf));
}
}
(void) close(pipefd[1]);
(void) pthread_join(tid, NULL);
if (di.zerr != 0) {
zfs_error_aux(zhp->zfs_hdl, strerror(di.zerr));
return (zfs_error(zhp->zfs_hdl, EZFS_DIFF, di.errbuf));
}
teardown_differ_info(&di);
return (0);
}

View File

@ -0,0 +1,452 @@
/*
* CDDL HEADER START
*
* 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]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <dlfcn.h>
#include <errno.h>
#include <libintl.h>
#include <link.h>
#include <pthread.h>
#include <strings.h>
#include <unistd.h>
#include <libzfs.h>
#include <fm/libtopo.h>
#include <sys/fm/protocol.h>
#include <sys/systeminfo.h>
#include "libzfs_impl.h"
/*
* This file is responsible for determining the relationship between I/O
* devices paths and physical locations. In the world of MPxIO and external
* enclosures, the device path is not synonymous with the physical location.
* If you remove a drive and insert it into a different slot, it will end up
* with the same path under MPxIO. If you recable storage enclosures, the
* device paths may change. All of this makes it difficult to implement the
* 'autoreplace' property, which is supposed to automatically manage disk
* replacement based on physical slot.
*
* In order to work around these limitations, we have a per-vdev FRU property
* that is the libtopo path (minus disk-specific authority information) to the
* physical location of the device on the system. This is an optional
* property, and is only needed when using the 'autoreplace' property or when
* generating FMA faults against vdevs.
*/
/*
* Because the FMA packages depend on ZFS, we have to dlopen() libtopo in case
* it is not present. We only need this once per library instance, so it is
* not part of the libzfs handle.
*/
static void *_topo_dlhandle;
static topo_hdl_t *(*_topo_open)(int, const char *, int *);
static void (*_topo_close)(topo_hdl_t *);
static char *(*_topo_snap_hold)(topo_hdl_t *, const char *, int *);
static void (*_topo_snap_release)(topo_hdl_t *);
static topo_walk_t *(*_topo_walk_init)(topo_hdl_t *, const char *,
topo_walk_cb_t, void *, int *);
static int (*_topo_walk_step)(topo_walk_t *, int);
static void (*_topo_walk_fini)(topo_walk_t *);
static void (*_topo_hdl_strfree)(topo_hdl_t *, char *);
static char *(*_topo_node_name)(tnode_t *);
static int (*_topo_prop_get_string)(tnode_t *, const char *, const char *,
char **, int *);
static int (*_topo_node_fru)(tnode_t *, nvlist_t **, nvlist_t *, int *);
static int (*_topo_fmri_nvl2str)(topo_hdl_t *, nvlist_t *, char **, int *);
static int (*_topo_fmri_strcmp_noauth)(topo_hdl_t *, const char *,
const char *);
#define ZFS_FRU_HASH_SIZE 257
static size_t
fru_strhash(const char *key)
{
ulong_t g, h = 0;
const char *p;
for (p = key; *p != '\0'; p++) {
h = (h << 4) + *p;
if ((g = (h & 0xf0000000)) != 0) {
h ^= (g >> 24);
h ^= g;
}
}
return (h % ZFS_FRU_HASH_SIZE);
}
static int
libzfs_fru_gather(topo_hdl_t *thp, tnode_t *tn, void *arg)
{
libzfs_handle_t *hdl = arg;
nvlist_t *fru;
char *devpath, *frustr;
int err;
libzfs_fru_t *frup;
size_t idx;
/*
* If this is the chassis node, and we don't yet have the system
* chassis ID, then fill in this value now.
*/
if (hdl->libzfs_chassis_id[0] == '\0' &&
strcmp(_topo_node_name(tn), "chassis") == 0) {
if (_topo_prop_get_string(tn, FM_FMRI_AUTHORITY,
FM_FMRI_AUTH_CHASSIS, &devpath, &err) == 0)
(void) strlcpy(hdl->libzfs_chassis_id, devpath,
sizeof (hdl->libzfs_chassis_id));
}
/*
* Skip non-disk nodes.
*/
if (strcmp(_topo_node_name(tn), "disk") != 0)
return (TOPO_WALK_NEXT);
/*
* Get the devfs path and FRU.
*/
if (_topo_prop_get_string(tn, "io", "devfs-path", &devpath, &err) != 0)
return (TOPO_WALK_NEXT);
if (libzfs_fru_lookup(hdl, devpath) != NULL) {
_topo_hdl_strfree(thp, devpath);
return (TOPO_WALK_NEXT);
}
if (_topo_node_fru(tn, &fru, NULL, &err) != 0) {
_topo_hdl_strfree(thp, devpath);
return (TOPO_WALK_NEXT);
}
/*
* Convert the FRU into a string.
*/
if (_topo_fmri_nvl2str(thp, fru, &frustr, &err) != 0) {
nvlist_free(fru);
_topo_hdl_strfree(thp, devpath);
return (TOPO_WALK_NEXT);
}
nvlist_free(fru);
/*
* Finally, we have a FRU string and device path. Add it to the hash.
*/
if ((frup = calloc(sizeof (libzfs_fru_t), 1)) == NULL) {
_topo_hdl_strfree(thp, devpath);
_topo_hdl_strfree(thp, frustr);
return (TOPO_WALK_NEXT);
}
if ((frup->zf_device = strdup(devpath)) == NULL ||
(frup->zf_fru = strdup(frustr)) == NULL) {
free(frup->zf_device);
free(frup);
_topo_hdl_strfree(thp, devpath);
_topo_hdl_strfree(thp, frustr);
return (TOPO_WALK_NEXT);
}
_topo_hdl_strfree(thp, devpath);
_topo_hdl_strfree(thp, frustr);
idx = fru_strhash(frup->zf_device);
frup->zf_chain = hdl->libzfs_fru_hash[idx];
hdl->libzfs_fru_hash[idx] = frup;
frup->zf_next = hdl->libzfs_fru_list;
hdl->libzfs_fru_list = frup;
return (TOPO_WALK_NEXT);
}
/*
* Called during initialization to setup the dynamic libtopo connection.
*/
#pragma init(libzfs_init_fru)
static void
libzfs_init_fru(void)
{
char path[MAXPATHLEN];
char isa[257];
#if defined(_LP64)
if (sysinfo(SI_ARCHITECTURE_64, isa, sizeof (isa)) < 0)
isa[0] = '\0';
#else
isa[0] = '\0';
#endif
(void) snprintf(path, sizeof (path),
"/usr/lib/fm/%s/libtopo.so", isa);
if ((_topo_dlhandle = dlopen(path, RTLD_LAZY)) == NULL)
return;
_topo_open = (topo_hdl_t *(*)())
dlsym(_topo_dlhandle, "topo_open");
_topo_close = (void (*)())
dlsym(_topo_dlhandle, "topo_close");
_topo_snap_hold = (char *(*)())
dlsym(_topo_dlhandle, "topo_snap_hold");
_topo_snap_release = (void (*)())
dlsym(_topo_dlhandle, "topo_snap_release");
_topo_walk_init = (topo_walk_t *(*)())
dlsym(_topo_dlhandle, "topo_walk_init");
_topo_walk_step = (int (*)())
dlsym(_topo_dlhandle, "topo_walk_step");
_topo_walk_fini = (void (*)())
dlsym(_topo_dlhandle, "topo_walk_fini");
_topo_hdl_strfree = (void (*)())
dlsym(_topo_dlhandle, "topo_hdl_strfree");
_topo_node_name = (char *(*)())
dlsym(_topo_dlhandle, "topo_node_name");
_topo_prop_get_string = (int (*)())
dlsym(_topo_dlhandle, "topo_prop_get_string");
_topo_node_fru = (int (*)())
dlsym(_topo_dlhandle, "topo_node_fru");
_topo_fmri_nvl2str = (int (*)())
dlsym(_topo_dlhandle, "topo_fmri_nvl2str");
_topo_fmri_strcmp_noauth = (int (*)())
dlsym(_topo_dlhandle, "topo_fmri_strcmp_noauth");
if (_topo_open == NULL || _topo_close == NULL ||
_topo_snap_hold == NULL || _topo_snap_release == NULL ||
_topo_walk_init == NULL || _topo_walk_step == NULL ||
_topo_walk_fini == NULL || _topo_hdl_strfree == NULL ||
_topo_node_name == NULL || _topo_prop_get_string == NULL ||
_topo_node_fru == NULL || _topo_fmri_nvl2str == NULL ||
_topo_fmri_strcmp_noauth == NULL) {
(void) dlclose(_topo_dlhandle);
_topo_dlhandle = NULL;
}
}
/*
* Refresh the mappings from device path -> FMRI. We do this by walking the
* hc topology looking for disk nodes, and recording the io/devfs-path and FRU.
* Note that we strip out the disk-specific authority information (serial,
* part, revision, etc) so that we are left with only the identifying
* characteristics of the slot (hc path and chassis-id).
*/
void
libzfs_fru_refresh(libzfs_handle_t *hdl)
{
int err;
char *uuid;
topo_hdl_t *thp;
topo_walk_t *twp;
if (_topo_dlhandle == NULL)
return;
/*
* Clear the FRU hash and initialize our basic structures.
*/
libzfs_fru_clear(hdl, B_FALSE);
if ((hdl->libzfs_topo_hdl = _topo_open(TOPO_VERSION,
NULL, &err)) == NULL)
return;
thp = hdl->libzfs_topo_hdl;
if ((uuid = _topo_snap_hold(thp, NULL, &err)) == NULL)
return;
_topo_hdl_strfree(thp, uuid);
if (hdl->libzfs_fru_hash == NULL &&
(hdl->libzfs_fru_hash =
calloc(ZFS_FRU_HASH_SIZE * sizeof (void *), 1)) == NULL)
return;
/*
* We now have a topo snapshot, so iterate over the hc topology looking
* for disks to add to the hash.
*/
twp = _topo_walk_init(thp, FM_FMRI_SCHEME_HC,
libzfs_fru_gather, hdl, &err);
if (twp != NULL) {
(void) _topo_walk_step(twp, TOPO_WALK_CHILD);
_topo_walk_fini(twp);
}
}
/*
* Given a devfs path, return the FRU for the device, if known. This will
* automatically call libzfs_fru_refresh() if it hasn't already been called by
* the consumer. The string returned is valid until the next call to
* libzfs_fru_refresh().
*/
const char *
libzfs_fru_lookup(libzfs_handle_t *hdl, const char *devpath)
{
size_t idx = fru_strhash(devpath);
libzfs_fru_t *frup;
if (hdl->libzfs_fru_hash == NULL)
libzfs_fru_refresh(hdl);
if (hdl->libzfs_fru_hash == NULL)
return (NULL);
for (frup = hdl->libzfs_fru_hash[idx]; frup != NULL;
frup = frup->zf_chain) {
if (strcmp(devpath, frup->zf_device) == 0)
return (frup->zf_fru);
}
return (NULL);
}
/*
* Given a fru path, return the device path. This will automatically call
* libzfs_fru_refresh() if it hasn't already been called by the consumer. The
* string returned is valid until the next call to libzfs_fru_refresh().
*/
const char *
libzfs_fru_devpath(libzfs_handle_t *hdl, const char *fru)
{
libzfs_fru_t *frup;
size_t idx;
if (hdl->libzfs_fru_hash == NULL)
libzfs_fru_refresh(hdl);
if (hdl->libzfs_fru_hash == NULL)
return (NULL);
for (idx = 0; idx < ZFS_FRU_HASH_SIZE; idx++) {
for (frup = hdl->libzfs_fru_hash[idx]; frup != NULL;
frup = frup->zf_next) {
if (_topo_fmri_strcmp_noauth(hdl->libzfs_topo_hdl,
fru, frup->zf_fru))
return (frup->zf_device);
}
}
return (NULL);
}
/*
* Change the stored FRU for the given vdev.
*/
int
zpool_fru_set(zpool_handle_t *zhp, uint64_t vdev_guid, const char *fru)
{
zfs_cmd_t zc = { 0 };
(void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
(void) strncpy(zc.zc_value, fru, sizeof (zc.zc_value));
zc.zc_guid = vdev_guid;
if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SETFRU, &zc) != 0)
return (zpool_standard_error_fmt(zhp->zpool_hdl, errno,
dgettext(TEXT_DOMAIN, "cannot set FRU")));
return (0);
}
/*
* Compare to two FRUs, ignoring any authority information.
*/
boolean_t
libzfs_fru_compare(libzfs_handle_t *hdl, const char *a, const char *b)
{
if (hdl->libzfs_fru_hash == NULL)
libzfs_fru_refresh(hdl);
if (hdl->libzfs_fru_hash == NULL)
return (strcmp(a, b) == 0);
return (_topo_fmri_strcmp_noauth(hdl->libzfs_topo_hdl, a, b));
}
/*
* This special function checks to see whether the FRU indicates it's supposed
* to be in the system chassis, but the chassis-id doesn't match. This can
* happen in a clustered case, where both head nodes have the same logical
* disk, but opening the device on the other head node is meaningless.
*/
boolean_t
libzfs_fru_notself(libzfs_handle_t *hdl, const char *fru)
{
const char *chassisid;
size_t len;
if (hdl->libzfs_fru_hash == NULL)
libzfs_fru_refresh(hdl);
if (hdl->libzfs_chassis_id[0] == '\0')
return (B_FALSE);
if (strstr(fru, "/chassis=0/") == NULL)
return (B_FALSE);
if ((chassisid = strstr(fru, ":chassis-id=")) == NULL)
return (B_FALSE);
chassisid += 12;
len = strlen(hdl->libzfs_chassis_id);
if (strncmp(chassisid, hdl->libzfs_chassis_id, len) == 0 &&
(chassisid[len] == '/' || chassisid[len] == ':'))
return (B_FALSE);
return (B_TRUE);
}
/*
* Clear memory associated with the FRU hash.
*/
void
libzfs_fru_clear(libzfs_handle_t *hdl, boolean_t final)
{
libzfs_fru_t *frup;
while ((frup = hdl->libzfs_fru_list) != NULL) {
hdl->libzfs_fru_list = frup->zf_next;
free(frup->zf_device);
free(frup->zf_fru);
free(frup);
}
hdl->libzfs_fru_list = NULL;
if (hdl->libzfs_topo_hdl != NULL) {
_topo_snap_release(hdl->libzfs_topo_hdl);
_topo_close(hdl->libzfs_topo_hdl);
hdl->libzfs_topo_hdl = NULL;
}
if (final) {
free(hdl->libzfs_fru_hash);
} else if (hdl->libzfs_fru_hash != NULL) {
bzero(hdl->libzfs_fru_hash,
ZFS_FRU_HASH_SIZE * sizeof (void *));
}
}

View File

@ -20,8 +20,7 @@
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _LIBFS_IMPL_H
@ -30,7 +29,6 @@
#include <sys/dmu.h>
#include <sys/fs/zfs.h>
#include <sys/zfs_ioctl.h>
#include <sys/zfs_acl.h>
#include <sys/spa.h>
#include <sys/nvpair.h>
@ -38,6 +36,8 @@
#include <libuutil.h>
#include <libzfs.h>
#include "zfs_ioctl_compat.h"
#ifdef __cplusplus
extern "C" {
#endif
@ -47,6 +47,13 @@ extern "C" {
#endif
#define VERIFY verify
typedef struct libzfs_fru {
char *zf_device;
char *zf_fru;
struct libzfs_fru *zf_chain;
struct libzfs_fru *zf_next;
} libzfs_fru_t;
struct libzfs_handle {
int libzfs_error;
int libzfs_fd;
@ -61,11 +68,17 @@ struct libzfs_handle {
char libzfs_desc[1024];
char *libzfs_log_str;
int libzfs_printerr;
int libzfs_storeerr; /* stuff error messages into buffer */
void *libzfs_sharehdl; /* libshare handle */
uint_t libzfs_shareflags;
boolean_t libzfs_mnttab_enable;
avl_tree_t libzfs_mnttab_cache;
int libzfs_pool_iter;
libzfs_fru_t **libzfs_fru_hash;
libzfs_fru_t *libzfs_fru_list;
char libzfs_chassis_id[256];
};
#define ZFSSHARE_MISS 0x01 /* Didn't find entry in cache */
struct zfs_handle {
@ -77,6 +90,7 @@ struct zfs_handle {
dmu_objset_stats_t zfs_dmustats;
nvlist_t *zfs_props;
nvlist_t *zfs_user_props;
nvlist_t *zfs_recvd_props;
boolean_t zfs_mntcheck;
char *zfs_mntopts;
uint8_t *zfs_props_table;
@ -112,7 +126,6 @@ typedef enum {
*/
typedef enum {
SHARED_NOT_SHARED = 0x0,
SHARED_ISCSI = 0x1,
SHARED_NFS = 0x2,
SHARED_SMB = 0x4
} zfs_share_type_t;
@ -122,6 +135,7 @@ int zfs_error_fmt(libzfs_handle_t *, int, const char *, ...);
void zfs_error_aux(libzfs_handle_t *, const char *, ...);
void *zfs_alloc(libzfs_handle_t *, size_t);
void *zfs_realloc(libzfs_handle_t *, void *, size_t, size_t);
char *zfs_asprintf(libzfs_handle_t *, const char *, ...);
char *zfs_strdup(libzfs_handle_t *, const char *);
int no_memory(libzfs_handle_t *);
@ -172,11 +186,11 @@ zfs_handle_t *make_dataset_handle(libzfs_handle_t *, const char *);
int zpool_open_silent(libzfs_handle_t *, const char *, zpool_handle_t **);
int zvol_create_link(libzfs_handle_t *, const char *);
int zvol_remove_link(libzfs_handle_t *, const char *);
int zpool_iter_zvol(zpool_handle_t *, int (*)(const char *, void *), void *);
boolean_t zpool_name_valid(libzfs_handle_t *, boolean_t, const char *);
int zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
boolean_t modifying);
void namespace_clear(libzfs_handle_t *);
/*
@ -190,7 +204,10 @@ extern int zfs_parse_options(char *, zfs_share_proto_t);
extern int zfs_unshare_proto(zfs_handle_t *,
const char *, zfs_share_proto_t *);
#ifdef __FreeBSD__
extern void libzfs_fru_clear(libzfs_handle_t *, boolean_t);
#ifndef sun
static int zfs_kernel_version = 0;
/*
* This is FreeBSD version of ioctl, because Solaris' ioctl() updates
@ -200,11 +217,23 @@ extern int zfs_unshare_proto(zfs_handle_t *,
static __inline int
zcmd_ioctl(int fd, unsigned long cmd, zfs_cmd_t *zc)
{
size_t oldsize;
int ret;
size_t oldsize, zfs_kernel_version_size;
int version, ret, cflag = ZFS_CMD_COMPAT_NONE;
zfs_kernel_version_size = sizeof(zfs_kernel_version);
if (zfs_kernel_version == 0) {
sysctlbyname("vfs.zfs.version.spa", &zfs_kernel_version,
&zfs_kernel_version_size, NULL, 0);
}
if (zfs_kernel_version == SPA_VERSION_15 ||
zfs_kernel_version == SPA_VERSION_14 ||
zfs_kernel_version == SPA_VERSION_13)
cflag = ZFS_CMD_COMPAT_V15;
oldsize = zc->zc_nvlist_dst_size;
ret = ioctl(fd, cmd, zc);
ret = zcmd_ioctl_compat(fd, cmd, zc, cflag);
if (ret == 0 && oldsize < zc->zc_nvlist_dst_size) {
ret = -1;
errno = ENOMEM;
@ -213,7 +242,7 @@ zcmd_ioctl(int fd, unsigned long cmd, zfs_cmd_t *zc)
return (ret);
}
#define ioctl(fd, cmd, zc) zcmd_ioctl((fd), (cmd), (zc))
#endif
#endif /* !sun */
#ifdef __cplusplus
}

View File

@ -19,12 +19,9 @@
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Pool import support functions.
*
@ -41,15 +38,18 @@
* using our derived config, and record the results.
*/
#include <ctype.h>
#include <devid.h>
#include <dirent.h>
#include <errno.h>
#include <libintl.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <thread_pool.h>
#include <libgeom.h>
#include <sys/vdev_impl.h>
@ -113,6 +113,7 @@ get_devid(const char *path)
return (ret);
}
/*
* Go through and fix up any path and/or devid information for the given vdev
* configuration.
@ -388,8 +389,6 @@ refresh_config(libzfs_handle_t *hdl, nvlist_t *config)
}
if (err) {
(void) zpool_standard_error(hdl, errno,
dgettext(TEXT_DOMAIN, "cannot discover pools"));
zcmd_free_nvlists(&zc);
return (NULL);
}
@ -403,6 +402,21 @@ refresh_config(libzfs_handle_t *hdl, nvlist_t *config)
return (nvl);
}
/*
* Determine if the vdev id is a hole in the namespace.
*/
boolean_t
vdev_is_hole(uint64_t *hole_array, uint_t holes, uint_t id)
{
for (int c = 0; c < holes; c++) {
/* Top-level is a hole */
if (hole_array[c] == id)
return (B_TRUE);
}
return (B_FALSE);
}
/*
* Convert our list of pools into the definitive set of configurations. We
* start by picking the best config for each toplevel vdev. Once that's done,
@ -425,17 +439,20 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok)
uint64_t version, guid;
uint_t children = 0;
nvlist_t **child = NULL;
uint_t holes;
uint64_t *hole_array, max_id;
uint_t c;
boolean_t isactive;
uint64_t hostid;
nvlist_t *nvl;
boolean_t found_one = B_FALSE;
boolean_t valid_top_config = B_FALSE;
if (nvlist_alloc(&ret, 0, 0) != 0)
goto nomem;
for (pe = pl->pools; pe != NULL; pe = pe->pe_next) {
uint64_t id;
uint64_t id, max_txg = 0;
if (nvlist_alloc(&config, NV_UNIQUE_NAME, 0) != 0)
goto nomem;
@ -463,6 +480,42 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok)
}
}
/*
* We rely on the fact that the max txg for the
* pool will contain the most up-to-date information
* about the valid top-levels in the vdev namespace.
*/
if (best_txg > max_txg) {
(void) nvlist_remove(config,
ZPOOL_CONFIG_VDEV_CHILDREN,
DATA_TYPE_UINT64);
(void) nvlist_remove(config,
ZPOOL_CONFIG_HOLE_ARRAY,
DATA_TYPE_UINT64_ARRAY);
max_txg = best_txg;
hole_array = NULL;
holes = 0;
max_id = 0;
valid_top_config = B_FALSE;
if (nvlist_lookup_uint64(tmp,
ZPOOL_CONFIG_VDEV_CHILDREN, &max_id) == 0) {
verify(nvlist_add_uint64(config,
ZPOOL_CONFIG_VDEV_CHILDREN,
max_id) == 0);
valid_top_config = B_TRUE;
}
if (nvlist_lookup_uint64_array(tmp,
ZPOOL_CONFIG_HOLE_ARRAY, &hole_array,
&holes) == 0) {
verify(nvlist_add_uint64_array(config,
ZPOOL_CONFIG_HOLE_ARRAY,
hole_array, holes) == 0);
}
}
if (!config_seen) {
/*
* Copy the relevant pieces of data to the pool
@ -522,6 +575,7 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok)
ZPOOL_CONFIG_VDEV_TREE, &nvtop) == 0);
verify(nvlist_lookup_uint64(nvtop, ZPOOL_CONFIG_ID,
&id) == 0);
if (id >= children) {
nvlist_t **newchild;
@ -542,9 +596,74 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok)
}
/*
* If we have information about all the top-levels then
* clean up the nvlist which we've constructed. This
* means removing any extraneous devices that are
* beyond the valid range or adding devices to the end
* of our array which appear to be missing.
*/
if (valid_top_config) {
if (max_id < children) {
for (c = max_id; c < children; c++)
nvlist_free(child[c]);
children = max_id;
} else if (max_id > children) {
nvlist_t **newchild;
newchild = zfs_alloc(hdl, (max_id) *
sizeof (nvlist_t *));
if (newchild == NULL)
goto nomem;
for (c = 0; c < children; c++)
newchild[c] = child[c];
free(child);
child = newchild;
children = max_id;
}
}
verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
&guid) == 0);
/*
* The vdev namespace may contain holes as a result of
* device removal. We must add them back into the vdev
* tree before we process any missing devices.
*/
if (holes > 0) {
ASSERT(valid_top_config);
for (c = 0; c < children; c++) {
nvlist_t *holey;
if (child[c] != NULL ||
!vdev_is_hole(hole_array, holes, c))
continue;
if (nvlist_alloc(&holey, NV_UNIQUE_NAME,
0) != 0)
goto nomem;
/*
* Holes in the namespace are treated as
* "hole" top-level vdevs and have a
* special flag set on them.
*/
if (nvlist_add_string(holey,
ZPOOL_CONFIG_TYPE,
VDEV_TYPE_HOLE) != 0 ||
nvlist_add_uint64(holey,
ZPOOL_CONFIG_ID, c) != 0 ||
nvlist_add_uint64(holey,
ZPOOL_CONFIG_GUID, 0ULL) != 0)
goto nomem;
child[c] = holey;
}
}
/*
* Look for any missing top-level vdevs. If this is the case,
* create a faked up 'missing' vdev as a placeholder. We cannot
@ -552,7 +671,7 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok)
* certain checks to make sure the vdev IDs match their location
* in the configuration.
*/
for (c = 0; c < children; c++)
for (c = 0; c < children; c++) {
if (child[c] == NULL) {
nvlist_t *missing;
if (nvlist_alloc(&missing, NV_UNIQUE_NAME,
@ -570,6 +689,7 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok)
}
child[c] = missing;
}
}
/*
* Put all of this pool's top-level vdevs into a root vdev.
@ -636,8 +756,11 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok)
continue;
}
if ((nvl = refresh_config(hdl, config)) == NULL)
goto error;
if ((nvl = refresh_config(hdl, config)) == NULL) {
nvlist_free(config);
config = NULL;
continue;
}
nvlist_free(config);
config = nvl;
@ -777,56 +900,216 @@ zpool_read_label(int fd, nvlist_t **config)
return (0);
}
typedef struct rdsk_node {
char *rn_name;
int rn_dfd;
libzfs_handle_t *rn_hdl;
nvlist_t *rn_config;
avl_tree_t *rn_avl;
avl_node_t rn_node;
boolean_t rn_nozpool;
} rdsk_node_t;
static int
geom_find_import(libzfs_handle_t *hdl, pool_list_t *pools)
slice_cache_compare(const void *arg1, const void *arg2)
{
char path[MAXPATHLEN];
struct gmesh mesh;
struct gclass *mp;
struct ggeom *gp;
struct gprovider *pp;
nvlist_t *config;
int fd, ret = 0;
const char *nm1 = ((rdsk_node_t *)arg1)->rn_name;
const char *nm2 = ((rdsk_node_t *)arg2)->rn_name;
char *nm1slice, *nm2slice;
int rv;
/*
* Go through and read the label configuration information from every
* GEOM provider, organizing the information according to pool GUID
* and toplevel GUID.
* slices zero and two are the most likely to provide results,
* so put those first
*/
fd = geom_gettree(&mesh);
assert(fd == 0);
LIST_FOREACH(mp, &mesh.lg_class, lg_class) {
LIST_FOREACH(gp, &mp->lg_geom, lg_geom) {
LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
if ((fd = g_open(pp->lg_name, 0)) < 0)
continue;
(void) snprintf(path, sizeof (path), "%s%s",
_PATH_DEV, pp->lg_name);
if ((zpool_read_label(fd, &config)) != 0) {
(void) g_close(fd);
(void) no_memory(hdl);
goto error;
}
(void) g_close(fd);
if (config == NULL)
continue;
if (add_config(hdl, pools, path, config) != 0) {
ret = -1;
goto error;
}
}
}
nm1slice = strstr(nm1, "s0");
nm2slice = strstr(nm2, "s0");
if (nm1slice && !nm2slice) {
return (-1);
}
error:
geom_deletetree(&mesh);
return (ret);
if (!nm1slice && nm2slice) {
return (1);
}
nm1slice = strstr(nm1, "s2");
nm2slice = strstr(nm2, "s2");
if (nm1slice && !nm2slice) {
return (-1);
}
if (!nm1slice && nm2slice) {
return (1);
}
rv = strcmp(nm1, nm2);
if (rv == 0)
return (0);
return (rv > 0 ? 1 : -1);
}
#ifdef sun
static void
check_one_slice(avl_tree_t *r, char *diskname, uint_t partno,
diskaddr_t size, uint_t blksz)
{
rdsk_node_t tmpnode;
rdsk_node_t *node;
char sname[MAXNAMELEN];
tmpnode.rn_name = &sname[0];
(void) snprintf(tmpnode.rn_name, MAXNAMELEN, "%s%u",
diskname, partno);
/*
* protect against division by zero for disk labels that
* contain a bogus sector size
*/
if (blksz == 0)
blksz = DEV_BSIZE;
/* too small to contain a zpool? */
if ((size < (SPA_MINDEVSIZE / blksz)) &&
(node = avl_find(r, &tmpnode, NULL)))
node->rn_nozpool = B_TRUE;
}
#endif /* sun */
static void
nozpool_all_slices(avl_tree_t *r, const char *sname)
{
#ifdef sun
char diskname[MAXNAMELEN];
char *ptr;
int i;
(void) strncpy(diskname, sname, MAXNAMELEN);
if (((ptr = strrchr(diskname, 's')) == NULL) &&
((ptr = strrchr(diskname, 'p')) == NULL))
return;
ptr[0] = 's';
ptr[1] = '\0';
for (i = 0; i < NDKMAP; i++)
check_one_slice(r, diskname, i, 0, 1);
ptr[0] = 'p';
for (i = 0; i <= FD_NUMPART; i++)
check_one_slice(r, diskname, i, 0, 1);
#endif /* sun */
}
static void
check_slices(avl_tree_t *r, int fd, const char *sname)
{
#ifdef sun
struct extvtoc vtoc;
struct dk_gpt *gpt;
char diskname[MAXNAMELEN];
char *ptr;
int i;
(void) strncpy(diskname, sname, MAXNAMELEN);
if ((ptr = strrchr(diskname, 's')) == NULL || !isdigit(ptr[1]))
return;
ptr[1] = '\0';
if (read_extvtoc(fd, &vtoc) >= 0) {
for (i = 0; i < NDKMAP; i++)
check_one_slice(r, diskname, i,
vtoc.v_part[i].p_size, vtoc.v_sectorsz);
} else if (efi_alloc_and_read(fd, &gpt) >= 0) {
/*
* on x86 we'll still have leftover links that point
* to slices s[9-15], so use NDKMAP instead
*/
for (i = 0; i < NDKMAP; i++)
check_one_slice(r, diskname, i,
gpt->efi_parts[i].p_size, gpt->efi_lbasize);
/* nodes p[1-4] are never used with EFI labels */
ptr[0] = 'p';
for (i = 1; i <= FD_NUMPART; i++)
check_one_slice(r, diskname, i, 0, 1);
efi_free(gpt);
}
#endif /* sun */
}
static void
zpool_open_func(void *arg)
{
rdsk_node_t *rn = arg;
struct stat64 statbuf;
nvlist_t *config;
int fd;
if (rn->rn_nozpool)
return;
if ((fd = openat64(rn->rn_dfd, rn->rn_name, O_RDONLY)) < 0) {
/* symlink to a device that's no longer there */
if (errno == ENOENT)
nozpool_all_slices(rn->rn_avl, rn->rn_name);
return;
}
/*
* Ignore failed stats. We only want regular
* files, character devs and block devs.
*/
if (fstat64(fd, &statbuf) != 0 ||
(!S_ISREG(statbuf.st_mode) &&
!S_ISCHR(statbuf.st_mode) &&
!S_ISBLK(statbuf.st_mode))) {
(void) close(fd);
return;
}
/* this file is too small to hold a zpool */
if (S_ISREG(statbuf.st_mode) &&
statbuf.st_size < SPA_MINDEVSIZE) {
(void) close(fd);
return;
} else if (!S_ISREG(statbuf.st_mode)) {
/*
* Try to read the disk label first so we don't have to
* open a bunch of minor nodes that can't have a zpool.
*/
check_slices(rn->rn_avl, fd, rn->rn_name);
}
if ((zpool_read_label(fd, &config)) != 0) {
(void) close(fd);
(void) no_memory(rn->rn_hdl);
return;
}
(void) close(fd);
rn->rn_config = config;
if (config != NULL) {
assert(rn->rn_nozpool == B_FALSE);
}
}
/*
* Given a file descriptor, clear (zero) the label information. This function
* is currently only used in the appliance stack as part of the ZFS sysevent
* module.
*/
int
zpool_clear_label(int fd)
{
struct stat64 statbuf;
int l;
vdev_label_t *label;
uint64_t size;
if (fstat64(fd, &statbuf) == -1)
return (0);
size = P2ALIGN_TYPED(statbuf.st_size, sizeof (vdev_label_t), uint64_t);
if ((label = calloc(sizeof (vdev_label_t), 1)) == NULL)
return (-1);
for (l = 0; l < VDEV_LABELS; l++) {
if (pwrite64(fd, label, sizeof (vdev_label_t),
label_offset(size, l)) != sizeof (vdev_label_t))
return (-1);
}
free(label);
return (0);
}
/*
@ -837,30 +1120,28 @@ geom_find_import(libzfs_handle_t *hdl, pool_list_t *pools)
* to import a specific pool.
*/
static nvlist_t *
zpool_find_import_impl(libzfs_handle_t *hdl, int argc, char **argv,
boolean_t active_ok, char *poolname, uint64_t guid)
zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg)
{
int i;
int i, dirs = iarg->paths;
DIR *dirp = NULL;
struct dirent64 *dp;
char path[MAXPATHLEN];
char *end;
char *end, **dir = iarg->path;
size_t pathleft;
struct stat64 statbuf;
nvlist_t *ret = NULL, *config;
nvlist_t *ret = NULL;
static char *default_dir = "/dev/dsk";
int fd;
pool_list_t pools = { 0 };
pool_entry_t *pe, *penext;
vdev_entry_t *ve, *venext;
config_entry_t *ce, *cenext;
name_entry_t *ne, *nenext;
avl_tree_t slice_cache;
rdsk_node_t *slice;
void *cookie;
verify(poolname == NULL || guid == 0);
if (argc == 0) {
argc = 1;
argv = &default_dir;
if (dirs == 0) {
dirs = 1;
dir = &default_dir;
}
/*
@ -868,15 +1149,15 @@ zpool_find_import_impl(libzfs_handle_t *hdl, int argc, char **argv,
* possible device, organizing the information according to pool GUID
* and toplevel GUID.
*/
for (i = 0; i < argc; i++) {
for (i = 0; i < dirs; i++) {
tpool_t *t;
char *rdsk;
int dfd;
/* use realpath to normalize the path */
if (realpath(argv[i], path) == 0) {
if (realpath(dir[i], path) == 0) {
(void) zfs_error_fmt(hdl, EZFS_BADPATH,
dgettext(TEXT_DOMAIN, "cannot open '%s'"),
argv[i]);
dgettext(TEXT_DOMAIN, "cannot open '%s'"), dir[i]);
goto error;
}
end = &path[strlen(path)];
@ -884,22 +1165,18 @@ zpool_find_import_impl(libzfs_handle_t *hdl, int argc, char **argv,
*end = 0;
pathleft = &path[sizeof (path)] - end;
if (strcmp(argv[i], default_dir) == 0) {
geom_find_import(hdl, &pools);
continue;
}
/*
* Using raw devices instead of block devices when we're
* reading the labels skips a bunch of slow operations during
* close(2) processing, so we replace /dev/dsk with /dev/rdsk.
*/
if (strcmp(path, "/dev/dsk/") == 0)
rdsk = "/dev/rdsk/";
rdsk = "/dev/";
else
rdsk = path;
if ((dirp = opendir(rdsk)) == NULL) {
if ((dfd = open64(rdsk, O_RDONLY)) < 0 ||
(dirp = fdopendir(dfd)) == NULL) {
zfs_error_aux(hdl, strerror(errno));
(void) zfs_error_fmt(hdl, EZFS_BADPATH,
dgettext(TEXT_DOMAIN, "cannot open '%s'"),
@ -907,6 +1184,41 @@ zpool_find_import_impl(libzfs_handle_t *hdl, int argc, char **argv,
goto error;
}
avl_create(&slice_cache, slice_cache_compare,
sizeof (rdsk_node_t), offsetof(rdsk_node_t, rn_node));
if (strcmp(rdsk, "/dev/") == 0) {
struct gmesh mesh;
struct gclass *mp;
struct ggeom *gp;
struct gprovider *pp;
errno = geom_gettree(&mesh);
if (errno != 0) {
zfs_error_aux(hdl, strerror(errno));
(void) zfs_error_fmt(hdl, EZFS_BADPATH,
dgettext(TEXT_DOMAIN, "cannot get GEOM tree"));
goto error;
}
LIST_FOREACH(mp, &mesh.lg_class, lg_class) {
LIST_FOREACH(gp, &mp->lg_geom, lg_geom) {
LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
slice = zfs_alloc(hdl, sizeof (rdsk_node_t));
slice->rn_name = zfs_strdup(hdl, pp->lg_name);
slice->rn_avl = &slice_cache;
slice->rn_dfd = dfd;
slice->rn_hdl = hdl;
slice->rn_nozpool = B_FALSE;
avl_add(&slice_cache, slice);
}
}
}
geom_deletetree(&mesh);
goto skipdir;
}
/*
* This is not MT-safe, but we have no MT consumers of libzfs
*/
@ -916,49 +1228,54 @@ zpool_find_import_impl(libzfs_handle_t *hdl, int argc, char **argv,
(name[1] == 0 || (name[1] == '.' && name[2] == 0)))
continue;
(void) snprintf(path, sizeof (path), "%s/%s", rdsk,
dp->d_name);
slice = zfs_alloc(hdl, sizeof (rdsk_node_t));
slice->rn_name = zfs_strdup(hdl, name);
slice->rn_avl = &slice_cache;
slice->rn_dfd = dfd;
slice->rn_hdl = hdl;
slice->rn_nozpool = B_FALSE;
avl_add(&slice_cache, slice);
}
skipdir:
/*
* create a thread pool to do all of this in parallel;
* rn_nozpool is not protected, so this is racy in that
* multiple tasks could decide that the same slice can
* not hold a zpool, which is benign. Also choose
* double the number of processors; we hold a lot of
* locks in the kernel, so going beyond this doesn't
* buy us much.
*/
t = tpool_create(1, 2 * sysconf(_SC_NPROCESSORS_ONLN),
0, NULL);
for (slice = avl_first(&slice_cache); slice;
(slice = avl_walk(&slice_cache, slice,
AVL_AFTER)))
(void) tpool_dispatch(t, zpool_open_func, slice);
tpool_wait(t);
tpool_destroy(t);
if ((fd = open64(path, O_RDONLY)) < 0)
continue;
/*
* Ignore failed stats. We only want regular
* files, character devs and block devs.
*/
if (fstat64(fd, &statbuf) != 0 ||
(!S_ISREG(statbuf.st_mode) &&
!S_ISCHR(statbuf.st_mode) &&
!S_ISBLK(statbuf.st_mode))) {
(void) close(fd);
continue;
}
if ((zpool_read_label(fd, &config)) != 0) {
(void) close(fd);
(void) no_memory(hdl);
goto error;
}
(void) close(fd);
if (config != NULL) {
cookie = NULL;
while ((slice = avl_destroy_nodes(&slice_cache,
&cookie)) != NULL) {
if (slice->rn_config != NULL) {
nvlist_t *config = slice->rn_config;
boolean_t matched = B_TRUE;
if (poolname != NULL) {
if (iarg->poolname != NULL) {
char *pname;
matched = nvlist_lookup_string(config,
ZPOOL_CONFIG_POOL_NAME,
&pname) == 0 &&
strcmp(poolname, pname) == 0;
} else if (guid != 0) {
strcmp(iarg->poolname, pname) == 0;
} else if (iarg->guid != 0) {
uint64_t this_guid;
matched = nvlist_lookup_uint64(config,
ZPOOL_CONFIG_POOL_GUID,
&this_guid) == 0 &&
guid == this_guid;
iarg->guid == this_guid;
}
if (!matched) {
nvlist_free(config);
@ -966,17 +1283,20 @@ zpool_find_import_impl(libzfs_handle_t *hdl, int argc, char **argv,
continue;
}
/* use the non-raw path for the config */
(void) strlcpy(end, name, pathleft);
(void) strlcpy(end, slice->rn_name, pathleft);
if (add_config(hdl, &pools, path, config) != 0)
goto error;
}
free(slice->rn_name);
free(slice);
}
avl_destroy(&slice_cache);
(void) closedir(dirp);
dirp = NULL;
}
ret = get_configs(hdl, &pools, active_ok);
ret = get_configs(hdl, &pools, iarg->can_be_active);
error:
for (pe = pools.pools; pe != NULL; pe = penext) {
@ -1010,27 +1330,12 @@ zpool_find_import_impl(libzfs_handle_t *hdl, int argc, char **argv,
nvlist_t *
zpool_find_import(libzfs_handle_t *hdl, int argc, char **argv)
{
return (zpool_find_import_impl(hdl, argc, argv, B_FALSE, NULL, 0));
}
importargs_t iarg = { 0 };
nvlist_t *
zpool_find_import_byname(libzfs_handle_t *hdl, int argc, char **argv,
char *pool)
{
return (zpool_find_import_impl(hdl, argc, argv, B_FALSE, pool, 0));
}
iarg.paths = argc;
iarg.path = argv;
nvlist_t *
zpool_find_import_byguid(libzfs_handle_t *hdl, int argc, char **argv,
uint64_t guid)
{
return (zpool_find_import_impl(hdl, argc, argv, B_FALSE, NULL, guid));
}
nvlist_t *
zpool_find_import_activeok(libzfs_handle_t *hdl, int argc, char **argv)
{
return (zpool_find_import_impl(hdl, argc, argv, B_TRUE, NULL, 0));
return (zpool_find_import_impl(hdl, &iarg));
}
/*
@ -1152,6 +1457,46 @@ zpool_find_import_cached(libzfs_handle_t *hdl, const char *cachefile,
return (pools);
}
static int
name_or_guid_exists(zpool_handle_t *zhp, void *data)
{
importargs_t *import = data;
int found = 0;
if (import->poolname != NULL) {
char *pool_name;
verify(nvlist_lookup_string(zhp->zpool_config,
ZPOOL_CONFIG_POOL_NAME, &pool_name) == 0);
if (strcmp(pool_name, import->poolname) == 0)
found = 1;
} else {
uint64_t pool_guid;
verify(nvlist_lookup_uint64(zhp->zpool_config,
ZPOOL_CONFIG_POOL_GUID, &pool_guid) == 0);
if (pool_guid == import->guid)
found = 1;
}
zpool_close(zhp);
return (found);
}
nvlist_t *
zpool_search_import(libzfs_handle_t *hdl, importargs_t *import)
{
verify(import->poolname == NULL || import->guid == 0);
if (import->unique)
import->exists = zpool_iter(hdl, name_or_guid_exists, import);
if (import->cachefile != NULL)
return (zpool_find_import_cached(hdl, import->cachefile,
import->poolname, import->guid));
return (zpool_find_import_impl(hdl, import));
}
boolean_t
find_guid(nvlist_t *nv, uint64_t guid)
@ -1251,6 +1596,17 @@ zpool_in_use(libzfs_handle_t *hdl, int fd, pool_state_t *state, char **namestr,
switch (stateval) {
case POOL_STATE_EXPORTED:
/*
* A pool with an exported state may in fact be imported
* read-only, so check the in-core state to see if it's
* active and imported read-only. If it is, set
* its state to active.
*/
if (pool_active(hdl, name, guid, &isactive) == 0 && isactive &&
(zhp = zpool_open_canfail(hdl, name)) != NULL &&
zpool_get_prop_int(zhp, ZPOOL_PROP_READONLY, NULL))
stateval = POOL_STATE_ACTIVE;
ret = B_TRUE;
break;

View File

@ -20,8 +20,7 @@
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@ -44,17 +43,14 @@
*
* zfs_is_shared_nfs()
* zfs_is_shared_smb()
* zfs_is_shared_iscsi()
* zfs_share_proto()
* zfs_shareall();
* zfs_share_iscsi()
* zfs_unshare_nfs()
* zfs_unshare_smb()
* zfs_unshareall_nfs()
* zfs_unshareall_smb()
* zfs_unshareall()
* zfs_unshareall_bypath()
* zfs_unshare_iscsi()
*
* The following functions are available for pool consumers, and will
* mount/unmount and share/unshare all datasets within pool:
@ -82,18 +78,12 @@
#include "libzfs_impl.h"
#include <libshare.h>
#define MAXISALEN 257 /* based on sysinfo(2) man page */
static int zfs_share_proto(zfs_handle_t *, zfs_share_proto_t *);
zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **,
zfs_share_proto_t);
static int (*iscsitgt_zfs_share)(const char *);
static int (*iscsitgt_zfs_unshare)(const char *);
static int (*iscsitgt_zfs_is_shared)(const char *);
static int (*iscsitgt_svc_online)();
/*
* The share protocols table must be in the same order as the zfs_share_prot_t
* enum in libzfs_impl.h
@ -125,29 +115,6 @@ zfs_share_proto_t share_all_proto[] = {
PROTO_END
};
#pragma init(zfs_iscsi_init)
static void
zfs_iscsi_init(void)
{
void *libiscsitgt;
if ((libiscsitgt = dlopen("/lib/libiscsitgt.so.1",
RTLD_LAZY | RTLD_GLOBAL)) == NULL ||
(iscsitgt_zfs_share = (int (*)(const char *))dlsym(libiscsitgt,
"iscsitgt_zfs_share")) == NULL ||
(iscsitgt_zfs_unshare = (int (*)(const char *))dlsym(libiscsitgt,
"iscsitgt_zfs_unshare")) == NULL ||
(iscsitgt_zfs_is_shared = (int (*)(const char *))dlsym(libiscsitgt,
"iscsitgt_zfs_is_shared")) == NULL ||
(iscsitgt_svc_online = (int (*)(const char *))dlsym(libiscsitgt,
"iscsitgt_svc_online")) == NULL) {
iscsitgt_zfs_share = NULL;
iscsitgt_zfs_unshare = NULL;
iscsitgt_zfs_is_shared = NULL;
iscsitgt_svc_online = NULL;
}
}
/*
* Search the sharetab for the given mountpoint and protocol, returning
* a zfs_share_type_t value.
@ -171,7 +138,7 @@ is_shared(libzfs_handle_t *hdl, const char *mountpoint, zfs_share_proto_t proto)
*tab = '\0';
if (strcmp(buf, mountpoint) == 0) {
#if defined(sun)
#ifdef sun
/*
* the protocol field is the third field
* skip over second field
@ -204,7 +171,7 @@ is_shared(libzfs_handle_t *hdl, const char *mountpoint, zfs_share_proto_t proto)
return (SHARED_NOT_SHARED);
}
#if 0
#ifdef sun
/*
* Returns true if the specified directory is empty. If we can't open the
* directory at all, return true so that the mount can fail with a more
@ -309,6 +276,12 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
else
(void) strlcpy(mntopts, options, sizeof (mntopts));
/*
* If the pool is imported read-only then all mounts must be read-only
*/
if (zpool_get_prop_int(zhp->zpool_hdl, ZPOOL_PROP_READONLY, NULL))
flags |= MS_RDONLY;
if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
return (0);
@ -323,7 +296,7 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
}
}
#if 0 /* FreeBSD: overlay mounts are not checked. */
#ifdef sun /* FreeBSD: overlay mounts are not checked. */
/*
* Determine if the mountpoint is empty. If so, refuse to perform the
* mount. We don't perform this check if MS_OVERLAY is specified, which
@ -354,6 +327,18 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
} else if (errno == EPERM) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"Insufficient privileges"));
} else if (errno == ENOTSUP) {
char buf[256];
int spa_version;
VERIFY(zfs_spa_version(zhp, &spa_version) == 0);
(void) snprintf(buf, sizeof (buf),
dgettext(TEXT_DOMAIN, "Can't mount a version %lld "
"file system on a version %d pool. Pool must be"
" upgraded to mount this file system."),
(u_longlong_t)zfs_prop_get_int(zhp,
ZFS_PROP_VERSION), spa_version);
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, buf));
} else {
zfs_error_aux(hdl, strerror(errno));
}
@ -374,7 +359,7 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
static int
unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags)
{
if (unmount(mountpoint, flags) != 0) {
if (umount2(mountpoint, flags) != 0) {
zfs_error_aux(hdl, strerror(errno));
return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED,
dgettext(TEXT_DOMAIN, "cannot unmount '%s'"),
@ -454,7 +439,7 @@ zfs_is_shared(zfs_handle_t *zhp)
zfs_share_proto_t *curr_proto;
if (ZFS_IS_VOLUME(zhp))
return (zfs_is_shared_iscsi(zhp));
return (B_FALSE);
for (curr_proto = share_all_proto; *curr_proto != PROTO_END;
curr_proto++)
@ -466,18 +451,14 @@ zfs_is_shared(zfs_handle_t *zhp)
int
zfs_share(zfs_handle_t *zhp)
{
if (ZFS_IS_VOLUME(zhp))
return (zfs_share_iscsi(zhp));
assert(!ZFS_IS_VOLUME(zhp));
return (zfs_share_proto(zhp, share_all_proto));
}
int
zfs_unshare(zfs_handle_t *zhp)
{
if (ZFS_IS_VOLUME(zhp))
return (zfs_unshare_iscsi(zhp));
assert(!ZFS_IS_VOLUME(zhp));
return (zfs_unshareall(zhp));
}
@ -525,7 +506,7 @@ zfs_is_shared_smb(zfs_handle_t *zhp, char **where)
* initialized in _zfs_init_libshare() are actually present.
*/
#if 0
#ifdef sun
static sa_handle_t (*_sa_init)(int);
static void (*_sa_fini)(sa_handle_t);
static sa_share_t (*_sa_find_share)(sa_handle_t, char *);
@ -552,7 +533,7 @@ static void (*_sa_update_sharetab_ts)(sa_handle_t);
static void
_zfs_init_libshare(void)
{
#if 0
#ifdef sun
void *libshare;
char path[MAXPATHLEN];
char isa[MAXISALEN];
@ -623,7 +604,7 @@ zfs_init_libshare(libzfs_handle_t *zhandle, int service)
{
int ret = SA_OK;
#if 0
#ifdef sun
if (_sa_init == NULL)
ret = SA_CONFIG_ERR;
@ -664,7 +645,7 @@ void
zfs_uninit_libshare(libzfs_handle_t *zhandle)
{
if (zhandle != NULL && zhandle->libzfs_sharehdl != NULL) {
#if 0
#ifdef sun
if (_sa_fini != NULL)
_sa_fini(zhandle->libzfs_sharehdl);
#endif
@ -681,7 +662,7 @@ zfs_uninit_libshare(libzfs_handle_t *zhandle)
int
zfs_parse_options(char *options, zfs_share_proto_t proto)
{
#if 0
#ifdef sun
if (_sa_parse_legacy_options != NULL) {
return (_sa_parse_legacy_options(NULL, options,
proto_table[proto].p_name));
@ -692,7 +673,7 @@ zfs_parse_options(char *options, zfs_share_proto_t proto)
#endif
}
#if 0
#ifdef sun
/*
* zfs_sa_find_share(handle, path)
*
@ -734,7 +715,7 @@ zfs_sa_disable_share(sa_share_t share, char *proto)
return (_sa_disable_share(share, proto));
return (SA_CONFIG_ERR);
}
#endif
#endif /* sun */
/*
* Share the given filesystem according to the options in the specified
@ -755,6 +736,16 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
return (0);
#ifdef sun
if ((ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) {
(void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
dgettext(TEXT_DOMAIN, "cannot share '%s': %s"),
zfs_get_name(zhp), _sa_errorstr != NULL ?
_sa_errorstr(ret) : "");
return (-1);
}
#endif
for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) {
/*
* Return success if there are no share options.
@ -774,13 +765,7 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED))
continue;
if (*curr_proto != PROTO_NFS) {
fprintf(stderr, "Unsupported share protocol: %d.\n",
*curr_proto);
continue;
}
#if 0
#ifdef sun
share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint);
if (share == NULL) {
/*
@ -819,6 +804,12 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
}
} else
#else
if (*curr_proto != PROTO_NFS) {
fprintf(stderr, "Unsupported share protocol: %d.\n",
*curr_proto);
continue;
}
if (strcmp(shareopts, "on") == 0)
error = fsshare(ZFS_EXPORTS_PATH, mountpoint, "");
else
@ -832,6 +823,7 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
zfs_get_name(zhp));
return (-1);
}
}
return (0);
}
@ -862,23 +854,58 @@ static int
unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint,
zfs_share_proto_t proto)
{
#ifdef sun
sa_share_t share;
int err;
char *mntpt;
/*
* Mountpoint could get trashed if libshare calls getmntany
* which it does during API initialization, so strdup the
* value.
*/
mntpt = zfs_strdup(hdl, mountpoint);
/* make sure libshare initialized */
if ((err = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) {
free(mntpt); /* don't need the copy anymore */
return (zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"),
name, _sa_errorstr(err)));
}
share = zfs_sa_find_share(hdl->libzfs_sharehdl, mntpt);
free(mntpt); /* don't need the copy anymore */
if (share != NULL) {
err = zfs_sa_disable_share(share, proto_table[proto].p_name);
if (err != SA_OK) {
return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"),
name, _sa_errorstr(err)));
}
} else {
return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
dgettext(TEXT_DOMAIN, "cannot unshare '%s': not found"),
name));
}
#else
char buf[MAXPATHLEN];
FILE *fp;
int error;
int err;
if (proto != PROTO_NFS) {
fprintf(stderr, "No SMB support in FreeBSD yet.\n");
return (EOPNOTSUPP);
}
error = fsunshare(ZFS_EXPORTS_PATH, mountpoint);
if (error != 0) {
zfs_error_aux(hdl, "%s", strerror(error));
err = fsunshare(ZFS_EXPORTS_PATH, mountpoint);
if (err != 0) {
zfs_error_aux(hdl, "%s", strerror(err));
return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
dgettext(TEXT_DOMAIN,
"cannot unshare '%s'"), name));
}
#endif
return (0);
}
@ -1011,99 +1038,29 @@ remove_mountpoint(zfs_handle_t *zhp)
}
}
boolean_t
zfs_is_shared_iscsi(zfs_handle_t *zhp)
void
libzfs_add_handle(get_all_cb_t *cbp, zfs_handle_t *zhp)
{
if (cbp->cb_alloc == cbp->cb_used) {
size_t newsz;
void *ptr;
/*
* If iscsi deamon isn't running then we aren't shared
*/
if (iscsitgt_svc_online && iscsitgt_svc_online() == 1)
return (B_FALSE);
else
return (iscsitgt_zfs_is_shared != NULL &&
iscsitgt_zfs_is_shared(zhp->zfs_name) != 0);
}
int
zfs_share_iscsi(zfs_handle_t *zhp)
{
char shareopts[ZFS_MAXPROPLEN];
const char *dataset = zhp->zfs_name;
libzfs_handle_t *hdl = zhp->zfs_hdl;
/*
* Return success if there are no share options.
*/
if (zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts,
sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0 ||
strcmp(shareopts, "off") == 0)
return (0);
/* We don't support iSCSI on FreeBSD yet. */
#ifdef TODO
if (iscsitgt_zfs_share == NULL || iscsitgt_zfs_share(dataset) != 0) {
int error = EZFS_SHAREISCSIFAILED;
/*
* If service isn't availabele and EPERM was
* returned then use special error.
*/
if (iscsitgt_svc_online && errno == EPERM &&
(iscsitgt_svc_online() != 0))
error = EZFS_ISCSISVCUNAVAIL;
return (zfs_error_fmt(hdl, error,
dgettext(TEXT_DOMAIN, "cannot share '%s'"), dataset));
newsz = cbp->cb_alloc ? cbp->cb_alloc * 2 : 64;
ptr = zfs_realloc(zhp->zfs_hdl,
cbp->cb_handles, cbp->cb_alloc * sizeof (void *),
newsz * sizeof (void *));
cbp->cb_handles = ptr;
cbp->cb_alloc = newsz;
}
#endif
return (0);
cbp->cb_handles[cbp->cb_used++] = zhp;
}
int
zfs_unshare_iscsi(zfs_handle_t *zhp)
{
const char *dataset = zfs_get_name(zhp);
libzfs_handle_t *hdl = zhp->zfs_hdl;
/* We don't support iSCSI on FreeBSD yet. */
#ifdef TODO
/*
* Return if the volume is not shared
*/
if (zfs_is_shared_iscsi(zhp) != SHARED_ISCSI)
return (0);
/*
* If this fails with ENODEV it indicates that zvol wasn't shared so
* we should return success in that case.
*/
if (iscsitgt_zfs_unshare == NULL ||
(iscsitgt_zfs_unshare(dataset) != 0 && errno != ENODEV)) {
if (errno == EPERM)
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"Insufficient privileges to unshare iscsi"));
return (zfs_error_fmt(hdl, EZFS_UNSHAREISCSIFAILED,
dgettext(TEXT_DOMAIN, "cannot unshare '%s'"), dataset));
}
#endif
return (0);
}
typedef struct mount_cbdata {
zfs_handle_t **cb_datasets;
int cb_used;
int cb_alloc;
} mount_cbdata_t;
static int
mount_cb(zfs_handle_t *zhp, void *data)
{
mount_cbdata_t *cbp = data;
get_all_cb_t *cbp = data;
if (!(zfs_get_type(zhp) & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME))) {
if (!(zfs_get_type(zhp) & ZFS_TYPE_FILESYSTEM)) {
zfs_close(zhp);
return (0);
}
@ -1113,25 +1070,16 @@ mount_cb(zfs_handle_t *zhp, void *data)
return (0);
}
if (cbp->cb_alloc == cbp->cb_used) {
void *ptr;
if ((ptr = zfs_realloc(zhp->zfs_hdl,
cbp->cb_datasets, cbp->cb_alloc * sizeof (void *),
cbp->cb_alloc * 2 * sizeof (void *))) == NULL)
return (-1);
cbp->cb_datasets = ptr;
cbp->cb_alloc *= 2;
libzfs_add_handle(cbp, zhp);
if (zfs_iter_filesystems(zhp, mount_cb, cbp) != 0) {
zfs_close(zhp);
return (-1);
}
cbp->cb_datasets[cbp->cb_used++] = zhp;
return (zfs_iter_filesystems(zhp, mount_cb, cbp));
return (0);
}
static int
dataset_cmp(const void *a, const void *b)
int
libzfs_dataset_cmp(const void *a, const void *b)
{
zfs_handle_t **za = (zfs_handle_t **)a;
zfs_handle_t **zb = (zfs_handle_t **)b;
@ -1169,7 +1117,7 @@ dataset_cmp(const void *a, const void *b)
int
zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
{
mount_cbdata_t cb = { 0 };
get_all_cb_t cb = { 0 };
libzfs_handle_t *hdl = zhp->zpool_hdl;
zfs_handle_t *zfsp;
int i, ret = -1;
@ -1178,23 +1126,17 @@ zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
/*
* Gather all non-snap datasets within the pool.
*/
if ((cb.cb_datasets = zfs_alloc(hdl, 4 * sizeof (void *))) == NULL)
return (-1);
cb.cb_alloc = 4;
if ((zfsp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_DATASET)) == NULL)
goto out;
cb.cb_datasets[0] = zfsp;
cb.cb_used = 1;
libzfs_add_handle(&cb, zfsp);
if (zfs_iter_filesystems(zfsp, mount_cb, &cb) != 0)
goto out;
/*
* Sort the datasets by mountpoint.
*/
qsort(cb.cb_datasets, cb.cb_used, sizeof (void *), dataset_cmp);
qsort(cb.cb_handles, cb.cb_used, sizeof (void *),
libzfs_dataset_cmp);
/*
* And mount all the datasets, keeping track of which ones
@ -1206,7 +1148,7 @@ zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
ret = 0;
for (i = 0; i < cb.cb_used; i++) {
if (zfs_mount(cb.cb_datasets[i], mntopts, flags) != 0)
if (zfs_mount(cb.cb_handles[i], mntopts, flags) != 0)
ret = -1;
else
good[i] = 1;
@ -1219,7 +1161,7 @@ zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
* zfs_alloc is supposed to exit if memory isn't available.
*/
for (i = 0; i < cb.cb_used; i++) {
if (good[i] && zfs_share(cb.cb_datasets[i]) != 0)
if (good[i] && zfs_share(cb.cb_handles[i]) != 0)
ret = -1;
}
@ -1227,34 +1169,12 @@ zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
out:
for (i = 0; i < cb.cb_used; i++)
zfs_close(cb.cb_datasets[i]);
free(cb.cb_datasets);
zfs_close(cb.cb_handles[i]);
free(cb.cb_handles);
return (ret);
}
static int
zvol_cb(const char *dataset, void *data)
{
libzfs_handle_t *hdl = data;
zfs_handle_t *zhp;
/*
* Ignore snapshots and ignore failures from non-existant datasets.
*/
if (strchr(dataset, '@') != NULL ||
(zhp = zfs_open(hdl, dataset, ZFS_TYPE_VOLUME)) == NULL)
return (0);
if (zfs_unshare_iscsi(zhp) != 0)
return (-1);
zfs_close(zhp);
return (0);
}
static int
mountpoint_compare(const void *a, const void *b)
{
@ -1264,6 +1184,8 @@ mountpoint_compare(const void *a, const void *b)
return (strcmp(mountb, mounta));
}
/* alias for 2002/240 */
#pragma weak zpool_unmount_datasets = zpool_disable_datasets
/*
* Unshare and unmount all datasets within the given pool. We don't want to
* rely on traversing the DSL to discover the filesystems within the pool,
@ -1271,46 +1193,38 @@ mountpoint_compare(const void *a, const void *b)
* arbitrarily (on I/O error, for example). Instead, we walk /etc/mnttab and
* gather all the filesystems that are currently mounted.
*/
#pragma weak zpool_unmount_datasets = zpool_disable_datasets
int
zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force)
{
int used, alloc;
struct statfs *sfs;
struct mnttab entry;
size_t namelen;
char **mountpoints = NULL;
zfs_handle_t **datasets = NULL;
libzfs_handle_t *hdl = zhp->zpool_hdl;
int i, j, n;
int i;
int ret = -1;
int flags = (force ? MS_FORCE : 0);
/*
* First unshare all zvols.
*/
if (zpool_iter_zvol(zhp, zvol_cb, hdl) != 0)
return (-1);
namelen = strlen(zhp->zpool_name);
rewind(hdl->libzfs_mnttab);
used = alloc = 0;
if ((n = getmntinfo(&sfs, MNT_WAIT)) == 0) {
fprintf(stderr, "getmntinfo(): %s\n", strerror(errno));
return (-1);
}
for (j = 0; j < n; j++) {
while (getmntent(hdl->libzfs_mnttab, &entry) == 0) {
/*
* Ignore non-ZFS entries.
*/
if (strcmp(sfs[j].f_fstypename, MNTTYPE_ZFS) != 0)
if (entry.mnt_fstype == NULL ||
strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
continue;
/*
* Ignore filesystems not within this pool.
*/
if (strncmp(sfs[j].f_mntfromname, zhp->zpool_name, namelen) != 0 ||
(sfs[j].f_mntfromname[namelen] != '/' &&
sfs[j].f_mntfromname[namelen] != '\0'))
if (entry.mnt_mountp == NULL ||
strncmp(entry.mnt_special, zhp->zpool_name, namelen) != 0 ||
(entry.mnt_special[namelen] != '/' &&
entry.mnt_special[namelen] != '\0'))
continue;
/*
@ -1348,7 +1262,7 @@ zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force)
}
if ((mountpoints[used] = zfs_strdup(hdl,
sfs[j].f_mntonname)) == NULL)
entry.mnt_mountp)) == NULL)
goto out;
/*
@ -1356,7 +1270,7 @@ zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force)
* is only used to determine if we need to remove the underlying
* mountpoint, so failure is not fatal.
*/
datasets[used] = make_dataset_handle(hdl, sfs[j].f_mntfromname);
datasets[used] = make_dataset_handle(hdl, entry.mnt_special);
used++;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@ -104,6 +103,13 @@ vdev_offlined(uint64_t state, uint64_t aux, uint64_t errs)
return (state == VDEV_STATE_OFFLINE);
}
/* ARGSUSED */
static int
vdev_removed(uint64_t state, uint64_t aux, uint64_t errs)
{
return (state == VDEV_STATE_REMOVED);
}
/*
* Detect if any leaf devices that have seen errors or could not be opened.
*/
@ -131,7 +137,7 @@ find_vdev_problem(nvlist_t *vdev, int (*func)(uint64_t, uint64_t, uint64_t))
if (find_vdev_problem(child[c], func))
return (B_TRUE);
} else {
verify(nvlist_lookup_uint64_array(vdev, ZPOOL_CONFIG_STATS,
verify(nvlist_lookup_uint64_array(vdev, ZPOOL_CONFIG_VDEV_STATS,
(uint64_t **)&vs, &c) == 0);
if (func(vs->vs_state, vs->vs_aux,
@ -166,7 +172,8 @@ check_status(nvlist_t *config, boolean_t isimport)
{
nvlist_t *nvroot;
vdev_stat_t *vs;
uint_t vsc;
pool_scan_stat_t *ps = NULL;
uint_t vsc, psc;
uint64_t nerr;
uint64_t version;
uint64_t stateval;
@ -177,15 +184,24 @@ check_status(nvlist_t *config, boolean_t isimport)
&version) == 0);
verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
&nvroot) == 0);
verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
(uint64_t **)&vs, &vsc) == 0);
verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
&stateval) == 0);
(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, &hostid);
/*
* Currently resilvering a vdev
*/
(void) nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_SCAN_STATS,
(uint64_t **)&ps, &psc);
if (ps && ps->pss_func == POOL_SCAN_RESILVER &&
ps->pss_state == DSS_SCANNING)
return (ZPOOL_STATUS_RESILVERING);
/*
* Pool last accessed by another system.
*/
(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, &hostid);
if (hostid != 0 && (unsigned long)hostid != gethostid() &&
stateval == POOL_STATE_ACTIVE)
return (ZPOOL_STATUS_HOSTID_MISMATCH);
@ -276,10 +292,10 @@ check_status(nvlist_t *config, boolean_t isimport)
return (ZPOOL_STATUS_OFFLINE_DEV);
/*
* Currently resilvering
* Removed device
*/
if (!vs->vs_scrub_complete && vs->vs_scrub_type == POOL_SCRUB_RESILVER)
return (ZPOOL_STATUS_RESILVERING);
if (find_vdev_problem(nvroot, vdev_removed))
return (ZPOOL_STATUS_REMOVED_DEV);
/*
* Outdated, but usable, version
@ -315,3 +331,68 @@ zpool_import_status(nvlist_t *config, char **msgid)
return (ret);
}
static void
dump_ddt_stat(const ddt_stat_t *dds, int h)
{
char refcnt[6];
char blocks[6], lsize[6], psize[6], dsize[6];
char ref_blocks[6], ref_lsize[6], ref_psize[6], ref_dsize[6];
if (dds == NULL || dds->dds_blocks == 0)
return;
if (h == -1)
(void) strcpy(refcnt, "Total");
else
zfs_nicenum(1ULL << h, refcnt, sizeof (refcnt));
zfs_nicenum(dds->dds_blocks, blocks, sizeof (blocks));
zfs_nicenum(dds->dds_lsize, lsize, sizeof (lsize));
zfs_nicenum(dds->dds_psize, psize, sizeof (psize));
zfs_nicenum(dds->dds_dsize, dsize, sizeof (dsize));
zfs_nicenum(dds->dds_ref_blocks, ref_blocks, sizeof (ref_blocks));
zfs_nicenum(dds->dds_ref_lsize, ref_lsize, sizeof (ref_lsize));
zfs_nicenum(dds->dds_ref_psize, ref_psize, sizeof (ref_psize));
zfs_nicenum(dds->dds_ref_dsize, ref_dsize, sizeof (ref_dsize));
(void) printf("%6s %6s %5s %5s %5s %6s %5s %5s %5s\n",
refcnt,
blocks, lsize, psize, dsize,
ref_blocks, ref_lsize, ref_psize, ref_dsize);
}
/*
* Print the DDT histogram and the column totals.
*/
void
zpool_dump_ddt(const ddt_stat_t *dds_total, const ddt_histogram_t *ddh)
{
int h;
(void) printf("\n");
(void) printf("bucket "
" allocated "
" referenced \n");
(void) printf("______ "
"______________________________ "
"______________________________\n");
(void) printf("%6s %6s %5s %5s %5s %6s %5s %5s %5s\n",
"refcnt",
"blocks", "LSIZE", "PSIZE", "DSIZE",
"blocks", "LSIZE", "PSIZE", "DSIZE");
(void) printf("%6s %6s %5s %5s %5s %6s %5s %5s %5s\n",
"------",
"------", "-----", "-----", "-----",
"------", "-----", "-----", "-----");
for (h = 0; h < 64; h++)
dump_ddt_stat(&ddh->ddh_stat[h], h);
dump_ddt_stat(dds_total, -1);
(void) printf("\n");
}

View File

@ -19,14 +19,18 @@
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Internal utility routines for the ZFS library.
*/
#include <sys/param.h>
#include <sys/linker.h>
#include <sys/module.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <libintl.h>
@ -46,6 +50,8 @@
#include "libzfs_impl.h"
#include "zfs_prop.h"
int aok;
int
libzfs_errno(libzfs_handle_t *hdl)
{
@ -70,7 +76,7 @@ libzfs_error_description(libzfs_handle_t *hdl)
case EZFS_BADPROP:
return (dgettext(TEXT_DOMAIN, "invalid property value"));
case EZFS_PROPREADONLY:
return (dgettext(TEXT_DOMAIN, "read only property"));
return (dgettext(TEXT_DOMAIN, "read-only property"));
case EZFS_PROPTYPE:
return (dgettext(TEXT_DOMAIN, "property doesn't apply to "
"datasets of this type"));
@ -90,12 +96,10 @@ libzfs_error_description(libzfs_handle_t *hdl)
case EZFS_BADSTREAM:
return (dgettext(TEXT_DOMAIN, "invalid backup stream"));
case EZFS_DSREADONLY:
return (dgettext(TEXT_DOMAIN, "dataset is read only"));
return (dgettext(TEXT_DOMAIN, "dataset is read-only"));
case EZFS_VOLTOOBIG:
return (dgettext(TEXT_DOMAIN, "volume size exceeds limit for "
"this system"));
case EZFS_VOLHASDATA:
return (dgettext(TEXT_DOMAIN, "volume has data"));
case EZFS_INVALIDNAME:
return (dgettext(TEXT_DOMAIN, "invalid name"));
case EZFS_BADRESTORE:
@ -138,16 +142,12 @@ libzfs_error_description(libzfs_handle_t *hdl)
return (dgettext(TEXT_DOMAIN, "smb remove share failed"));
case EZFS_SHARESMBFAILED:
return (dgettext(TEXT_DOMAIN, "smb add share failed"));
case EZFS_ISCSISVCUNAVAIL:
return (dgettext(TEXT_DOMAIN,
"iscsitgt service need to be enabled by "
"a privileged user"));
case EZFS_DEVLINKS:
return (dgettext(TEXT_DOMAIN, "failed to create /dev links"));
case EZFS_PERM:
return (dgettext(TEXT_DOMAIN, "permission denied"));
case EZFS_NOSPC:
return (dgettext(TEXT_DOMAIN, "out of space"));
case EZFS_FAULT:
return (dgettext(TEXT_DOMAIN, "bad address"));
case EZFS_IO:
return (dgettext(TEXT_DOMAIN, "I/O error"));
case EZFS_INTR:
@ -161,12 +161,6 @@ libzfs_error_description(libzfs_handle_t *hdl)
return (dgettext(TEXT_DOMAIN, "recursive dataset dependency"));
case EZFS_NOHISTORY:
return (dgettext(TEXT_DOMAIN, "no history available"));
case EZFS_UNSHAREISCSIFAILED:
return (dgettext(TEXT_DOMAIN,
"iscsitgtd failed request to unshare"));
case EZFS_SHAREISCSIFAILED:
return (dgettext(TEXT_DOMAIN,
"iscsitgtd failed request to share"));
case EZFS_POOLPROPS:
return (dgettext(TEXT_DOMAIN, "failed to retrieve "
"pool properties"));
@ -194,9 +188,6 @@ libzfs_error_description(libzfs_handle_t *hdl)
case EZFS_NODELEGATION:
return (dgettext(TEXT_DOMAIN, "delegated administration is "
"disabled on pool"));
case EZFS_PERMRDONLY:
return (dgettext(TEXT_DOMAIN, "snapshot permissions cannot be"
" modified"));
case EZFS_BADCACHE:
return (dgettext(TEXT_DOMAIN, "invalid or missing cache file"));
case EZFS_ISL2CACHE:
@ -213,6 +204,31 @@ libzfs_error_description(libzfs_handle_t *hdl)
case EZFS_UNPLAYED_LOGS:
return (dgettext(TEXT_DOMAIN, "log device has unplayed intent "
"logs"));
case EZFS_REFTAG_RELE:
return (dgettext(TEXT_DOMAIN, "no such tag on this dataset"));
case EZFS_REFTAG_HOLD:
return (dgettext(TEXT_DOMAIN, "tag already exists on this "
"dataset"));
case EZFS_TAGTOOLONG:
return (dgettext(TEXT_DOMAIN, "tag too long"));
case EZFS_PIPEFAILED:
return (dgettext(TEXT_DOMAIN, "pipe create failed"));
case EZFS_THREADCREATEFAILED:
return (dgettext(TEXT_DOMAIN, "thread create failed"));
case EZFS_POSTSPLIT_ONLINE:
return (dgettext(TEXT_DOMAIN, "disk was split from this pool "
"into a new one"));
case EZFS_SCRUBBING:
return (dgettext(TEXT_DOMAIN, "currently scrubbing; "
"use 'zpool scrub -s' to cancel current scrub"));
case EZFS_NO_SCRUB:
return (dgettext(TEXT_DOMAIN, "there is no active scrub"));
case EZFS_DIFF:
return (dgettext(TEXT_DOMAIN, "unable to generate diffs"));
case EZFS_DIFFDATA:
return (dgettext(TEXT_DOMAIN, "invalid diff data"));
case EZFS_POOLREADONLY:
return (dgettext(TEXT_DOMAIN, "pool is read-only"));
case EZFS_UNKNOWN:
return (dgettext(TEXT_DOMAIN, "unknown error"));
default:
@ -301,6 +317,10 @@ zfs_common_error(libzfs_handle_t *hdl, int error, const char *fmt,
zfs_verror(hdl, EZFS_IO, fmt, ap);
return (-1);
case EFAULT:
zfs_verror(hdl, EZFS_FAULT, fmt, ap);
return (-1);
case EINTR:
zfs_verror(hdl, EZFS_INTR, fmt, ap);
return (-1);
@ -357,9 +377,7 @@ zfs_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
zfs_verror(hdl, EZFS_BUSY, fmt, ap);
break;
case EROFS:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"snapshot permissions cannot be modified"));
zfs_verror(hdl, EZFS_PERMRDONLY, fmt, ap);
zfs_verror(hdl, EZFS_POOLREADONLY, fmt, ap);
break;
case ENAMETOOLONG:
zfs_verror(hdl, EZFS_NAMETOOLONG, fmt, ap);
@ -373,7 +391,7 @@ zfs_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
zfs_verror(hdl, EZFS_POOLUNAVAIL, fmt, ap);
break;
default:
zfs_error_aux(hdl, strerror(errno));
zfs_error_aux(hdl, strerror(error));
zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
break;
}
@ -445,12 +463,17 @@ zpool_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
case EDQUOT:
zfs_verror(hdl, EZFS_NOSPC, fmt, ap);
return (-1);
case EAGAIN:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"pool I/O is currently suspended"));
zfs_verror(hdl, EZFS_POOLUNAVAIL, fmt, ap);
break;
case EROFS:
zfs_verror(hdl, EZFS_POOLREADONLY, fmt, ap);
break;
default:
zfs_error_aux(hdl, strerror(error));
zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
@ -483,6 +506,29 @@ zfs_alloc(libzfs_handle_t *hdl, size_t size)
return (data);
}
/*
* A safe form of asprintf() which will die if the allocation fails.
*/
/*PRINTFLIKE2*/
char *
zfs_asprintf(libzfs_handle_t *hdl, const char *fmt, ...)
{
va_list ap;
char *ret;
int err;
va_start(ap, fmt);
err = vasprintf(&ret, fmt, ap);
va_end(ap);
if (err < 0)
(void) no_memory(hdl);
return (ret);
}
/*
* A safe form of realloc(), which also zeroes newly allocated space.
*/
@ -573,7 +619,7 @@ libzfs_load(void)
/* Not present in kernel, try loading it. */
if (kldload("zfs") < 0 || modfind("zfs") < 0) {
if (errno != EEXIST)
return (error);
return (-1);
}
}
return (0);
@ -584,17 +630,18 @@ libzfs_init(void)
{
libzfs_handle_t *hdl;
if ((hdl = calloc(sizeof (libzfs_handle_t), 1)) == NULL) {
if ((hdl = calloc(1, sizeof (libzfs_handle_t))) == NULL) {
return (NULL);
}
if (libzfs_load() < 0) {
free(hdl);
return (NULL);
}
if ((hdl->libzfs_fd = open(ZFS_DEV, O_RDWR)) < 0) {
if (libzfs_load() == 0)
hdl->libzfs_fd = open(ZFS_DEV, O_RDWR);
if (hdl->libzfs_fd < 0) {
free(hdl);
return (NULL);
}
free(hdl);
return (NULL);
}
if ((hdl->libzfs_mnttab = fopen(MNTTAB, "r")) == NULL) {
@ -624,6 +671,9 @@ libzfs_fini(libzfs_handle_t *hdl)
if (hdl->libzfs_log_str)
(void) free(hdl->libzfs_log_str);
zpool_free_handles(hdl);
#ifdef sun
libzfs_fru_clear(hdl, B_TRUE);
#endif
namespace_clear(hdl);
libzfs_mnttab_fini(hdl);
free(hdl);
@ -656,7 +706,9 @@ zfs_get_pool_handle(const zfs_handle_t *zhp)
zfs_handle_t *
zfs_path_to_zhandle(libzfs_handle_t *hdl, char *path, zfs_type_t argtype)
{
struct statfs statbuf;
struct stat64 statbuf;
struct extmnttab entry;
int ret;
if (path[0] != '/' && strncmp(path, "./", strlen("./")) != 0) {
/*
@ -665,18 +717,42 @@ zfs_path_to_zhandle(libzfs_handle_t *hdl, char *path, zfs_type_t argtype)
return (zfs_open(hdl, path, argtype));
}
if (statfs(path, &statbuf) != 0) {
if (stat64(path, &statbuf) != 0) {
(void) fprintf(stderr, "%s: %s\n", path, strerror(errno));
return (NULL);
}
if (strcmp(statbuf.f_fstypename, MNTTYPE_ZFS) != 0) {
#ifdef sun
rewind(hdl->libzfs_mnttab);
while ((ret = getextmntent(hdl->libzfs_mnttab, &entry, 0)) == 0) {
if (makedevice(entry.mnt_major, entry.mnt_minor) ==
statbuf.st_dev) {
break;
}
}
#else
{
struct statfs sfs;
if (statfs(path, &sfs) != 0) {
(void) fprintf(stderr, "%s: %s\n", path,
strerror(errno));
ret = -1;
}
statfs2mnttab(&sfs, &entry);
}
#endif /* sun */
if (ret != 0) {
return (NULL);
}
if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) {
(void) fprintf(stderr, gettext("'%s': not a ZFS filesystem\n"),
path);
return (NULL);
}
return (zfs_open(hdl, statbuf.f_mntfromname, ZFS_TYPE_FILESYSTEM));
return (zfs_open(hdl, entry.mnt_special, ZFS_TYPE_FILESYSTEM));
}
/*
@ -687,7 +763,7 @@ int
zcmd_alloc_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, size_t len)
{
if (len == 0)
len = 2048;
len = 16 * 1024;
zc->zc_nvlist_dst_size = len;
if ((zc->zc_nvlist_dst = (uint64_t)(uintptr_t)
zfs_alloc(hdl, zc->zc_nvlist_dst_size)) == 0)
@ -813,6 +889,8 @@ zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type)
"PROPERTY"));
cbp->cb_colwidths[GET_COL_VALUE] = strlen(dgettext(TEXT_DOMAIN,
"VALUE"));
cbp->cb_colwidths[GET_COL_RECVD] = strlen(dgettext(TEXT_DOMAIN,
"RECEIVED"));
cbp->cb_colwidths[GET_COL_SOURCE] = strlen(dgettext(TEXT_DOMAIN,
"SOURCE"));
@ -826,7 +904,7 @@ zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type)
* inheriting from the longest name. This is acceptable because in the
* majority of cases 'SOURCE' is the last column displayed, and we don't
* use the width anyway. Note that the 'VALUE' column can be oversized,
* if the name of the property is much longer the any values we find.
* if the name of the property is much longer than any values we find.
*/
for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
/*
@ -857,6 +935,11 @@ zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type)
pl->pl_width > cbp->cb_colwidths[GET_COL_VALUE])
cbp->cb_colwidths[GET_COL_VALUE] = pl->pl_width;
/* 'RECEIVED' column. */
if (pl != cbp->cb_proplist &&
pl->pl_recvd_width > cbp->cb_colwidths[GET_COL_RECVD])
cbp->cb_colwidths[GET_COL_RECVD] = pl->pl_recvd_width;
/*
* 'NAME' and 'SOURCE' columns
*/
@ -872,7 +955,7 @@ zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type)
/*
* Now go through and print the headers.
*/
for (i = 0; i < 4; i++) {
for (i = 0; i < ZFS_GET_NCOLS; i++) {
switch (cbp->cb_columns[i]) {
case GET_COL_NAME:
title = dgettext(TEXT_DOMAIN, "NAME");
@ -883,6 +966,9 @@ zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type)
case GET_COL_VALUE:
title = dgettext(TEXT_DOMAIN, "VALUE");
break;
case GET_COL_RECVD:
title = dgettext(TEXT_DOMAIN, "RECEIVED");
break;
case GET_COL_SOURCE:
title = dgettext(TEXT_DOMAIN, "SOURCE");
break;
@ -891,7 +977,8 @@ zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type)
}
if (title != NULL) {
if (i == 3 || cbp->cb_columns[i + 1] == 0)
if (i == (ZFS_GET_NCOLS - 1) ||
cbp->cb_columns[i + 1] == GET_COL_NONE)
(void) printf("%s", title);
else
(void) printf("%-*s ",
@ -909,7 +996,7 @@ zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type)
void
zprop_print_one_property(const char *name, zprop_get_cbdata_t *cbp,
const char *propname, const char *value, zprop_source_t sourcetype,
const char *source)
const char *source, const char *recvd_value)
{
int i;
const char *str;
@ -924,7 +1011,7 @@ zprop_print_one_property(const char *name, zprop_get_cbdata_t *cbp,
if (cbp->cb_first)
zprop_print_headers(cbp, cbp->cb_type);
for (i = 0; i < 4; i++) {
for (i = 0; i < ZFS_GET_NCOLS; i++) {
switch (cbp->cb_columns[i]) {
case GET_COL_NAME:
str = name;
@ -961,14 +1048,21 @@ zprop_print_one_property(const char *name, zprop_get_cbdata_t *cbp,
"inherited from %s", source);
str = buf;
break;
case ZPROP_SRC_RECEIVED:
str = "received";
break;
}
break;
case GET_COL_RECVD:
str = (recvd_value == NULL ? "-" : recvd_value);
break;
default:
continue;
}
if (cbp->cb_columns[i + 1] == 0)
if (cbp->cb_columns[i + 1] == GET_COL_NONE)
(void) printf("%s", str);
else if (cbp->cb_scripted)
(void) printf("%s\t", str);
@ -976,7 +1070,6 @@ zprop_print_one_property(const char *name, zprop_get_cbdata_t *cbp,
(void) printf("%-*s ",
cbp->cb_colwidths[cbp->cb_columns[i]],
str);
}
(void) printf("\n");
@ -1038,7 +1131,7 @@ zfs_nicestrtonum(libzfs_handle_t *hdl, const char *value, uint64_t *num)
return (-1);
}
/* Rely on stroull() to process the numeric portion. */
/* Rely on strtoull() to process the numeric portion. */
errno = 0;
*num = strtoull(value, &end, 10);

View File

@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <assert.h>
@ -36,20 +35,24 @@
#include <sys/zfs_context.h>
#include <sys/zmod.h>
#include <sys/utsname.h>
#include <sys/systeminfo.h>
/*
* Emulation of kernel services in userland.
*/
int hz = 119; /* frequency when using gethrtime() >> 23 for lbolt */
int aok;
uint64_t physmem;
vnode_t *rootdir = (vnode_t *)0xabcd1234;
char hw_serial[11];
char hw_serial[HW_HOSTID_LEN];
struct utsname utsname = {
"userland", "libzpool", "1", "1", "na"
};
/* this only exists to have its address taken */
struct proc p0;
/*
* =========================================================================
* threads
@ -137,7 +140,7 @@ mutex_tryenter(kmutex_t *mp)
{
ASSERT(mp->initialized == B_TRUE);
ASSERT(mp->m_owner != (void *)-1UL);
if (mutex_trylock(&mp->m_lock) == 0) {
if (0 == mutex_trylock(&mp->m_lock)) {
ASSERT(mp->m_owner == NULL);
mp->m_owner = curthread;
return (1);
@ -150,7 +153,7 @@ void
mutex_exit(kmutex_t *mp)
{
ASSERT(mp->initialized == B_TRUE);
ASSERT(mp->m_owner == curthread);
ASSERT(mutex_owner(mp) == curthread);
mp->m_owner = NULL;
VERIFY(mutex_unlock(&mp->m_lock) == 0);
}
@ -308,9 +311,9 @@ cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime)
struct timeval tv;
clock_t delta;
abstime += lbolt;
abstime += ddi_get_lbolt();
top:
delta = abstime - lbolt;
delta = abstime - ddi_get_lbolt();
if (delta <= 0)
return (-1);
@ -432,10 +435,7 @@ vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
*vpp = vp = umem_zalloc(sizeof (vnode_t), UMEM_NOFAIL);
vp->v_fd = fd;
if (S_ISCHR(st.st_mode))
ioctl(fd, DIOCGMEDIASIZE, &vp->v_size);
else
vp->v_size = st.st_size;
vp->v_size = st.st_size;
vp->v_path = spa_strdup(path);
return (0);
@ -497,6 +497,24 @@ vn_close(vnode_t *vp, int openflag, cred_t *cr, kthread_t *td)
umem_free(vp, sizeof (vnode_t));
}
/*
* At a minimum we need to update the size since vdev_reopen()
* will no longer call vn_openat().
*/
int
fop_getattr(vnode_t *vp, vattr_t *vap)
{
struct stat64 st;
if (fstat64(vp->v_fd, &st) == -1) {
close(vp->v_fd);
return (errno);
}
vap->va_size = st.st_size;
return (0);
}
#ifdef ZFS_DEBUG
/*
@ -811,6 +829,17 @@ ddi_strtoul(const char *hw_serial, char **nptr, int base, unsigned long *result)
return (0);
}
int
ddi_strtoull(const char *str, char **nptr, int base, u_longlong_t *result)
{
char *end;
*result = strtoull(str, &end, base);
if (*result == 0)
return (errno);
return (0);
}
/*
* =========================================================================
* kernel emulation setup & teardown
@ -836,8 +865,8 @@ kernel_init(int mode)
dprintf("physmem = %llu pages (%.2f GB)\n", physmem,
(double)physmem * sysconf(_SC_PAGE_SIZE) / (1ULL << 30));
snprintf(hw_serial, sizeof (hw_serial), "%lu",
(unsigned long)gethostid());
(void) snprintf(hw_serial, sizeof (hw_serial), "%lu",
(mode & FWRITE) ? (unsigned long)gethostid() : 0);
VERIFY((random_fd = open("/dev/random", O_RDONLY)) != -1);
VERIFY((urandom_fd = open("/dev/urandom", O_RDONLY)) != -1);
@ -852,6 +881,8 @@ kernel_fini(void)
{
spa_fini();
system_taskq_fini();
close(random_fd);
close(urandom_fd);
@ -942,3 +973,72 @@ ksiddomain_rele(ksiddomain_t *ksid)
spa_strfree(ksid->kd_name);
umem_free(ksid, sizeof (ksiddomain_t));
}
/*
* Do not change the length of the returned string; it must be freed
* with strfree().
*/
char *
kmem_asprintf(const char *fmt, ...)
{
int size;
va_list adx;
char *buf;
va_start(adx, fmt);
size = vsnprintf(NULL, 0, fmt, adx) + 1;
va_end(adx);
buf = kmem_alloc(size, KM_SLEEP);
va_start(adx, fmt);
size = vsnprintf(buf, size, fmt, adx);
va_end(adx);
return (buf);
}
/* ARGSUSED */
int
zfs_onexit_fd_hold(int fd, minor_t *minorp)
{
*minorp = 0;
return (0);
}
/* ARGSUSED */
void
zfs_onexit_fd_rele(int fd)
{
}
/* ARGSUSED */
int
zfs_onexit_add_cb(minor_t minor, void (*func)(void *), void *data,
uint64_t *action_handle)
{
return (0);
}
/* ARGSUSED */
int
zfs_onexit_del_cb(minor_t minor, uint64_t action_handle, boolean_t fire)
{
return (0);
}
/* ARGSUSED */
int
zfs_onexit_cb_data(minor_t minor, uint64_t action_handle, void **data)
{
return (0);
}
#ifdef __FreeBSD__
/* ARGSUSED */
int
zvol_create_minors(const char *name)
{
return (0);
}
#endif

View File

@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _SYS_ZFS_CONTEXT_H
@ -59,6 +58,7 @@ extern "C" {
#include <time.h>
#include <math.h>
#include <umem.h>
#include <inttypes.h>
#include <fsshare.h>
#include <sys/note.h>
#include <sys/types.h>
@ -80,7 +80,9 @@ extern "C" {
#include <sys/u8_textprep.h>
#include <sys/kernel.h>
#include <sys/disk.h>
#include <sys/sysevent.h>
#include <sys/sysevent/eventdefs.h>
#include <sys/sysevent/dev.h>
#include <machine/atomic.h>
#define ZFS_EXPORTS_PATH "/etc/zfs/exports"
@ -119,20 +121,27 @@ extern void vpanic(const char *, __va_list);
#define fm_panic panic
extern int aok;
/* This definition is copied from assert.h. */
#if defined(__STDC__)
#if __STDC_VERSION__ - 0 >= 199901L
#define verify(EX) (void)((EX) || (__assert(#EX, __FILE__, __LINE__), 0))
#define zverify(EX) (void)((EX) || (aok) || \
(__assert(#EX, __FILE__, __LINE__), 0))
#else
#define verify(EX) (void)((EX) || (__assert(#EX, __FILE__, __LINE__), 0))
#define zverify(EX) (void)((EX) || (aok) || \
(__assert(#EX, __FILE__, __LINE__), 0))
#endif /* __STDC_VERSION__ - 0 >= 199901L */
#else
#define verify(EX) (void)((EX) || (_assert("EX", __FILE__, __LINE__), 0))
#define zverify(EX) (void)((EX) || (aok) || \
(_assert("EX", __FILE__, __LINE__), 0))
#endif /* __STDC__ */
#define VERIFY verify
#define ASSERT assert
#define VERIFY zverify
#define ASSERT zverify
#undef assert
#define assert zverify
extern void __assert(const char *, const char *, int);
@ -143,7 +152,7 @@ extern void __assert(const char *, const char *, int);
#define VERIFY3_IMPL(LEFT, OP, RIGHT, TYPE) do { \
const TYPE __left = (TYPE)(LEFT); \
const TYPE __right = (TYPE)(RIGHT); \
if (!(__left OP __right)) { \
if (!(__left OP __right) && (!aok)) { \
char *__buf = alloca(256); \
(void) snprintf(__buf, 256, "%s %s %s (0x%llx %s 0x%llx)", \
#LEFT, #OP, #RIGHT, \
@ -209,6 +218,18 @@ typedef struct kthread kthread_t;
#define thread_create(stk, stksize, func, arg, len, pp, state, pri) \
zk_thread_create(func, arg)
#define thread_exit() thr_exit(NULL)
#define thread_join(t) panic("libzpool cannot join threads")
#define newproc(f, a, cid, pri, ctp, pid) (ENOSYS)
/* in libzpool, p0 exists only to have its address taken */
struct proc {
uintptr_t this_is_never_used_dont_dereference_it;
};
extern struct proc p0;
#define PS_NONE -1
extern kthread_t *zk_thread_create(void (*func)(), void *arg);
@ -225,8 +246,11 @@ typedef struct kmutex {
} kmutex_t;
#define MUTEX_DEFAULT USYNC_THREAD
#undef MUTEX_HELD
#undef MUTEX_HELD
#undef MUTEX_NOT_HELD
#define MUTEX_HELD(m) ((m)->m_owner == curthread)
#define MUTEX_NOT_HELD(m) (!MUTEX_HELD(m))
#define _mutex_held(m) pthread_mutex_isowned_np(m)
/*
* Argh -- we have to get cheesy here because the kernel and userland
@ -234,6 +258,7 @@ typedef struct kmutex {
*/
//extern int _mutex_init(mutex_t *mp, int type, void *arg);
//extern int _mutex_destroy(mutex_t *mp);
//extern int _mutex_owned(mutex_t *mp);
#define mutex_init(mp, b, c, d) zmutex_init((kmutex_t *)(mp))
#define mutex_destroy(mp) zmutex_destroy((kmutex_t *)(mp))
@ -305,6 +330,7 @@ extern void cv_broadcast(kcondvar_t *cv);
#define KM_PUSHPAGE KM_SLEEP
#define KM_NOSLEEP UMEM_DEFAULT
#define KMC_NODEBUG UMC_NODEBUG
#define KMC_NOTOUCH 0 /* not needed for userland caches */
#define kmem_alloc(_s, _f) umem_alloc(_s, _f)
#define kmem_zalloc(_s, _f) umem_zalloc(_s, _f)
#define kmem_free(_b, _s) umem_free(_b, _s)
@ -315,10 +341,21 @@ extern void cv_broadcast(kcondvar_t *cv);
#define kmem_cache_alloc(_c, _f) umem_cache_alloc(_c, _f)
#define kmem_cache_free(_c, _b) umem_cache_free(_c, _b)
#define kmem_debugging() 0
#define kmem_cache_reap_now(c)
#define kmem_cache_reap_now(_c) /* nothing */
#define kmem_cache_set_move(_c, _cb) /* nothing */
#define POINTER_INVALIDATE(_pp) /* nothing */
#define POINTER_IS_VALID(_p) 0
typedef umem_cache_t kmem_cache_t;
typedef enum kmem_cbrc {
KMEM_CBRC_YES,
KMEM_CBRC_NO,
KMEM_CBRC_LATER,
KMEM_CBRC_DONT_NEED,
KMEM_CBRC_DONT_KNOW
} kmem_cbrc_t;
/*
* Task queues
*/
@ -329,23 +366,30 @@ typedef void (task_func_t)(void *);
#define TASKQ_PREPOPULATE 0x0001
#define TASKQ_CPR_SAFE 0x0002 /* Use CPR safe protocol */
#define TASKQ_DYNAMIC 0x0004 /* Use dynamic thread scheduling */
#define TASKQ_THREADS_CPU_PCT 0x0008 /* Use dynamic thread scheduling */
#define TASKQ_THREADS_CPU_PCT 0x0008 /* Scale # threads by # cpus */
#define TASKQ_DC_BATCH 0x0010 /* Mark threads as batch */
#define TQ_SLEEP KM_SLEEP /* Can block for memory */
#define TQ_NOSLEEP KM_NOSLEEP /* cannot block for memory; may fail */
#define TQ_NOQUEUE 0x02 /* Do not enqueue if can't dispatch */
#define TQ_NOQUEUE 0x02 /* Do not enqueue if can't dispatch */
#define TQ_FRONT 0x08 /* Queue in front */
extern taskq_t *system_taskq;
extern taskq_t *taskq_create(const char *, int, pri_t, int, int, uint_t);
#define taskq_create_proc(a, b, c, d, e, p, f) \
(taskq_create(a, b, c, d, e, f))
#define taskq_create_sysdc(a, b, d, e, p, dc, f) \
(taskq_create(a, b, maxclsyspri, d, e, f))
extern taskqid_t taskq_dispatch(taskq_t *, task_func_t, void *, uint_t);
extern void taskq_destroy(taskq_t *);
extern void taskq_wait(taskq_t *);
extern int taskq_member(taskq_t *, void *);
extern void system_taskq_init(void);
extern void system_taskq_fini(void);
#define taskq_dispatch_safe(tq, func, arg, task) \
taskq_dispatch((tq), (func), (arg), TQ_SLEEP)
#define taskq_dispatch_safe(tq, func, arg, flags, task) \
taskq_dispatch((tq), (func), (arg), (flags))
#define XVA_MAPSIZE 3
#define XVA_MAGIC 0x78766174
@ -359,6 +403,7 @@ typedef struct vnode {
char *v_path;
} vnode_t;
#define AV_SCANSTAMP_SZ 32 /* length of anti-virus scanstamp */
typedef struct xoptattr {
timestruc_t xoa_createtime; /* Create time of file */
@ -374,6 +419,10 @@ typedef struct xoptattr {
uint8_t xoa_opaque;
uint8_t xoa_av_quarantined;
uint8_t xoa_av_modified;
uint8_t xoa_av_scanstamp[AV_SCANSTAMP_SZ];
uint8_t xoa_reparse;
uint8_t xoa_offline;
uint8_t xoa_sparse;
} xoptattr_t;
typedef struct vattr {
@ -420,13 +469,15 @@ typedef struct vsecattr {
#define CRCREAT 0
extern int fop_getattr(vnode_t *vp, vattr_t *vap);
#define VOP_CLOSE(vp, f, c, o, cr, ct) 0
#define VOP_PUTPAGE(vp, of, sz, fl, cr, ct) 0
#define VOP_GETATTR(vp, vap, cr) ((vap)->va_size = (vp)->v_size, 0)
#define VOP_GETATTR(vp, vap, cr) fop_getattr((vp), (vap));
#define VOP_FSYNC(vp, f, cr, ct) fsync((vp)->v_fd)
#define VN_RELE(vp) vn_close(vp, 0, NULL, NULL)
#define VN_RELE(vp) vn_close(vp, 0, NULL, NULL)
#define VN_RELE_ASYNC(vp, taskq) vn_close(vp, 0, NULL, NULL)
#define vn_lock(vp, type)
@ -460,13 +511,18 @@ extern vnode_t *rootdir;
/*
* Random stuff
*/
#define lbolt (gethrtime() >> 23)
#define lbolt64 (gethrtime() >> 23)
//#define hz 119 /* frequency when using gethrtime() >> 23 for lbolt */
#define ddi_get_lbolt() (gethrtime() >> 23)
#define ddi_get_lbolt64() (gethrtime() >> 23)
#define hz 119 /* frequency when using gethrtime() >> 23 for lbolt */
extern void delay(clock_t ticks);
#define gethrestime_sec() time(NULL)
#define gethrestime(t) \
do {\
(t)->tv_sec = gethrestime_sec();\
(t)->tv_nsec = 0;\
} while (0);
#define max_ncpus 64
@ -475,6 +531,9 @@ extern void delay(clock_t ticks);
#define CPU_SEQID (thr_self() & (max_ncpus - 1))
#define kcred NULL
#define CRED() NULL
#ifndef ptob
#define ptob(x) ((x) * PAGESIZE)
#endif
@ -516,14 +575,20 @@ typedef struct callb_cpr {
#define zone_dataset_visible(x, y) (1)
#define INGLOBALZONE(z) (1)
extern char *kmem_asprintf(const char *fmt, ...);
#define strfree(str) kmem_free((str), strlen(str)+1)
/*
* Hostname information
*/
extern struct utsname utsname;
extern char hw_serial[];
extern char hw_serial[]; /* for userland-emulated hostid access */
extern int ddi_strtoul(const char *str, char **nptr, int base,
unsigned long *result);
extern int ddi_strtoull(const char *str, char **nptr, int base,
u_longlong_t *result);
/* ZFS Boot Related stuff. */
struct _buf {
@ -563,7 +628,6 @@ extern zoneid_t getzoneid(void);
#define lbolt (gethrtime() >> 23)
#define lbolt64 (gethrtime() >> 23)
extern int hz;
extern uint64_t physmem;
#define gethrestime_sec() time(NULL)
@ -593,6 +657,9 @@ void ksiddomain_rele(ksiddomain_t *);
typedef uint32_t idmap_rid_t;
#define DDI_SLEEP KM_SLEEP
#define ddi_log_sysevent(_a, _b, _c, _d, _e, _f, _g) (0)
#define SX_SYSINIT(name, lock, desc)
#define SYSCTL_DECL(...)

View File

@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@ -49,6 +49,8 @@ struct taskq {
int tq_nalloc;
int tq_minalloc;
int tq_maxalloc;
kcondvar_t tq_maxalloc_cv;
int tq_maxalloc_wait;
task_t *tq_freelist;
task_t tq_task;
};
@ -57,26 +59,36 @@ static task_t *
task_alloc(taskq_t *tq, int tqflags)
{
task_t *t;
int rv;
if ((t = tq->tq_freelist) != NULL && tq->tq_nalloc >= tq->tq_minalloc) {
again: if ((t = tq->tq_freelist) != NULL && tq->tq_nalloc >= tq->tq_minalloc) {
tq->tq_freelist = t->task_next;
} else {
mutex_exit(&tq->tq_lock);
if (tq->tq_nalloc >= tq->tq_maxalloc) {
if (!(tqflags & KM_SLEEP)) {
mutex_enter(&tq->tq_lock);
if (!(tqflags & KM_SLEEP))
return (NULL);
}
/*
* We don't want to exceed tq_maxalloc, but we can't
* wait for other tasks to complete (and thus free up
* task structures) without risking deadlock with
* the caller. So, we just delay for one second
* to throttle the allocation rate.
* to throttle the allocation rate. If we have tasks
* complete before one second timeout expires then
* taskq_ent_free will signal us and we will
* immediately retry the allocation.
*/
delay(hz);
tq->tq_maxalloc_wait++;
rv = cv_timedwait(&tq->tq_maxalloc_cv,
&tq->tq_lock, ddi_get_lbolt() + hz);
tq->tq_maxalloc_wait--;
if (rv > 0)
goto again; /* signaled */
}
mutex_exit(&tq->tq_lock);
t = kmem_alloc(sizeof (task_t), tqflags);
mutex_enter(&tq->tq_lock);
if (t != NULL)
tq->tq_nalloc++;
@ -96,6 +108,9 @@ task_free(taskq_t *tq, task_t *t)
kmem_free(t, sizeof (task_t));
mutex_enter(&tq->tq_lock);
}
if (tq->tq_maxalloc_wait)
cv_signal(&tq->tq_maxalloc_cv);
}
taskqid_t
@ -114,8 +129,13 @@ taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t tqflags)
mutex_exit(&tq->tq_lock);
return (0);
}
t->task_next = &tq->tq_task;
t->task_prev = tq->tq_task.task_prev;
if (tqflags & TQ_FRONT) {
t->task_next = tq->tq_task.task_next;
t->task_prev = &tq->tq_task;
} else {
t->task_next = &tq->tq_task;
t->task_prev = tq->tq_task.task_prev;
}
t->task_next->task_prev = t;
t->task_prev->task_next = t;
t->task_func = func;
@ -191,6 +211,7 @@ taskq_create(const char *name, int nthreads, pri_t pri,
mutex_init(&tq->tq_lock, NULL, MUTEX_DEFAULT, NULL);
cv_init(&tq->tq_dispatch_cv, NULL, CV_DEFAULT, NULL);
cv_init(&tq->tq_wait_cv, NULL, CV_DEFAULT, NULL);
cv_init(&tq->tq_maxalloc_cv, NULL, CV_DEFAULT, NULL);
tq->tq_flags = flags | TASKQ_ACTIVE;
tq->tq_active = nthreads;
tq->tq_nthreads = nthreads;
@ -247,6 +268,7 @@ taskq_destroy(taskq_t *tq)
mutex_destroy(&tq->tq_lock);
cv_destroy(&tq->tq_dispatch_cv);
cv_destroy(&tq->tq_wait_cv);
cv_destroy(&tq->tq_maxalloc_cv);
kmem_free(tq, sizeof (taskq_t));
}
@ -272,3 +294,10 @@ system_taskq_init(void)
system_taskq = taskq_create("system_taskq", 64, minclsyspri, 4, 512,
TASKQ_DYNAMIC | TASKQ_PREPOPULATE);
}
void
system_taskq_fini(void)
{
taskq_destroy(system_taskq);
system_taskq = NULL; /* defensive */
}

View File

@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <assert.h>
@ -90,7 +89,7 @@ show_vdev_stats(const char *desc, const char *ctype, nvlist_t *nv, int indent)
if (is_log)
prefix = "log ";
if (nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
if (nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
(uint64_t **)&vs, &c) != 0)
vs = &v0;

View File

@ -1,4 +1,4 @@
#! /usr/bin/python2.4
#! /usr/bin/python2.6
#
# CDDL HEADER START
#
@ -19,8 +19,7 @@
#
# CDDL HEADER END
#
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
#
"""

View File

@ -1,4 +1,4 @@
#! /usr/bin/python2.4
#! /usr/bin/python2.6
#
# CDDL HEADER START
#
@ -19,8 +19,7 @@
#
# CDDL HEADER END
#
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
#
"""This module implements the "zfs allow" and "zfs unallow" subcommands.
@ -204,8 +203,8 @@ def decodeid(w, toidfunc, fmt):
perms_subcmd = dict(
create=_("Must also have the 'mount' ability"),
destroy=_("Must also have the 'mount' ability"),
snapshot=_("Must also have the 'mount' ability"),
rollback=_("Must also have the 'mount' ability"),
snapshot="",
rollback="",
clone=_("""Must also have the 'create' ability and 'mount'
\t\t\t\tability in the origin file system"""),
promote=_("""Must also have the 'mount'
@ -217,6 +216,9 @@ def decodeid(w, toidfunc, fmt):
mount=_("Allows mount/umount of ZFS datasets"),
share=_("Allows sharing file systems over NFS or SMB\n\t\t\t\tprotocols"),
send="",
hold=_("Allows adding a user hold to a snapshot"),
release=_("Allows releasing a user hold which\n\t\t\t\tmight destroy the snapshot"),
diff=_("Allows lookup of paths within a dataset,\n\t\t\t\tgiven an object number. Ordinary users need this\n\t\t\t\tin order to use zfs diff"),
)
perms_other = dict(
@ -265,7 +267,7 @@ def print_perms():
print(fmt % (name, _("property"), ""))
def do_allow():
"""Implementes the "zfs allow" and "zfs unallow" subcommands."""
"""Implements the "zfs allow" and "zfs unallow" subcommands."""
un = (sys.argv[1] == "unallow")
def usage(msg=None):
@ -320,7 +322,7 @@ def usage(msg=None):
if sys.argv[2] == "-h":
# hack to make "zfs allow -h" work
usage()
ds = zfs.dataset.Dataset(sys.argv[2])
ds = zfs.dataset.Dataset(sys.argv[2], snaps=False)
p = dict()
for (fs, raw) in ds.get_fsacl().items():

View File

@ -1,4 +1,4 @@
#! /usr/bin/python2.4
#! /usr/bin/python2.6
#
# CDDL HEADER START
#
@ -19,8 +19,7 @@
#
# CDDL HEADER END
#
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
#
"""Implements the Dataset class, providing methods for manipulating ZFS
@ -109,7 +108,7 @@ def __init__(self, name, props=None,
types is an iterable of strings specifying which types
of datasets are permitted. Accepted strings are
"filesystem" and "volume". Defaults to acceptying all
"filesystem" and "volume". Defaults to accepting all
types.
snaps is a boolean specifying if snapshots are acceptable.
@ -203,3 +202,33 @@ def get_fsacl(self):
Return a dict("whostr": { "perm" -> None })."""
return zfs.ioctl.get_fsacl(self.name)
def get_holds(self):
"""Get the user holds on this Dataset.
Return a dict("tag": timestamp)."""
return zfs.ioctl.get_holds(self.name)
def snapshots_fromcmdline(dsnames, recursive):
for dsname in dsnames:
if not "@" in dsname:
raise zfs.util.ZFSError(errno.EINVAL,
_("cannot open %s") % dsname,
_("operation only applies to snapshots"))
try:
ds = Dataset(dsname)
yield ds
except zfs.util.ZFSError, e:
if not recursive or e.errno != errno.ENOENT:
raise
if recursive:
(base, snapname) = dsname.split('@')
parent = Dataset(base)
for child in parent.descendents():
try:
yield Dataset(child.name + "@" +
snapname)
except zfs.util.ZFSError, e:
if e.errno != errno.ENOENT:
raise

View File

@ -1,4 +1,4 @@
#! /usr/bin/python2.4
#! /usr/bin/python2.6
#
# CDDL HEADER START
#
@ -19,8 +19,7 @@
#
# CDDL HEADER END
#
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
#
import zfs.userspace

View File

@ -0,0 +1,75 @@
#! /usr/bin/python2.6
#
# CDDL HEADER START
#
# 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]
#
# CDDL HEADER END
#
# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
#
"""This module implements the "zfs holds" subcommand.
The only public interface is the zfs.holds.do_holds() function."""
import optparse
import sys
import errno
import time
import zfs.util
import zfs.dataset
import zfs.table
_ = zfs.util._
def do_holds():
"""Implements the "zfs holds" subcommand."""
def usage(msg=None):
parser.print_help()
if msg:
print
parser.exit("zfs: error: " + msg)
else:
parser.exit()
u = _("""holds [-r] <snapshot> ...""")
parser = optparse.OptionParser(usage=u, prog="zfs")
parser.add_option("-r", action="store_true", dest="recursive",
help=_("list holds recursively"))
(options, args) = parser.parse_args(sys.argv[2:])
if len(args) < 1:
usage(_("missing snapshot argument"))
fields = ("name", "tag", "timestamp")
rjustfields = ()
printing = False
gotone = False
t = zfs.table.Table(fields, rjustfields)
for ds in zfs.dataset.snapshots_fromcmdline(args, options.recursive):
gotone = True
for tag, tm in ds.get_holds().iteritems():
val = {"name": ds.name, "tag": tag,
"timestamp": time.ctime(tm)}
t.addline(ds.name, val)
printing = True
if printing:
t.printme()
elif not gotone:
raise zfs.util.ZFSError(errno.ENOENT, _("no matching datasets"))

View File

@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@ -29,8 +29,6 @@
#include <strings.h>
#include <unistd.h>
#include <libnvpair.h>
#include <idmap.h>
#include <zone.h>
#include <libintl.h>
#include <libzfs.h>
#include <libzfs_impl.h>
@ -45,10 +43,6 @@ static int zfsdevfd;
#define _(s) dgettext(TEXT_DOMAIN, s)
#ifdef sun
extern int sid_to_id(char *sid, boolean_t user, uid_t *id);
#endif /* sun */
/*PRINTFLIKE1*/
static void
seterr(char *fmt, ...)
@ -66,7 +60,7 @@ seterr(char *fmt, ...)
static char cmdstr[HIS_MAX_RECORD_LEN];
static int
ioctl_with_cmdstr(unsigned long ioc, zfs_cmd_t *zc)
ioctl_with_cmdstr(int ioc, zfs_cmd_t *zc)
{
int err;
@ -138,8 +132,7 @@ dict2nvl(PyObject *d)
nvlist_t *nvl;
int err;
PyObject *key, *value;
// int pos = 0;
Py_ssize_t pos = 0;
int pos = 0;
if (!PyDict_Check(d)) {
PyErr_SetObject(PyExc_ValueError, d);
@ -205,7 +198,7 @@ add_ds_props(zfs_cmd_t *zc, PyObject *nvl)
/* On error, returns NULL but does not set python exception. */
static PyObject *
ioctl_with_dstnv(unsigned long ioc, zfs_cmd_t *zc)
ioctl_with_dstnv(int ioc, zfs_cmd_t *zc)
{
int nvsz = 2048;
void *nvbuf;
@ -236,7 +229,7 @@ ioctl_with_dstnv(unsigned long ioc, zfs_cmd_t *zc)
static PyObject *
py_next_dataset(PyObject *self, PyObject *args)
{
unsigned long ioc;
int ioc;
uint64_t cookie;
zfs_cmd_t zc = { 0 };
int snaps;
@ -352,6 +345,25 @@ py_set_fsacl(PyObject *self, PyObject *args)
Py_RETURN_NONE;
}
static PyObject *
py_get_holds(PyObject *self, PyObject *args)
{
zfs_cmd_t zc = { 0 };
char *name;
PyObject *nvl;
if (!PyArg_ParseTuple(args, "s", &name))
return (NULL);
(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
nvl = ioctl_with_dstnv(ZFS_IOC_GET_HOLDS, &zc);
if (nvl == NULL)
seterr(_("cannot get holds for %s"), name);
return (nvl);
}
static PyObject *
py_userspace_many(PyObject *self, PyObject *args)
{
@ -439,80 +451,6 @@ py_userspace_upgrade(PyObject *self, PyObject *args)
Py_RETURN_NONE;
}
static PyObject *
py_sid_to_id(PyObject *self, PyObject *args)
{
#ifdef sun
char *sid;
int err, isuser;
uid_t id;
if (!PyArg_ParseTuple(args, "si", &sid, &isuser))
return (NULL);
err = sid_to_id(sid, isuser, &id);
if (err) {
PyErr_SetString(PyExc_KeyError, sid);
return (NULL);
}
return (Py_BuildValue("I", id));
#else /* sun */
return (NULL);
#endif /* sun */
}
/*
* Translate the sid string ("S-1-...") to the user@domain name, if
* possible. There should be a better way to do this, but for now we
* just translate to the (possibly ephemeral) uid and then back again.
*/
static PyObject *
py_sid_to_name(PyObject *self, PyObject *args)
{
#ifdef sun
char *sid;
int err, isuser;
uid_t id;
char *name, *domain;
char buf[256];
if (!PyArg_ParseTuple(args, "si", &sid, &isuser))
return (NULL);
err = sid_to_id(sid, isuser, &id);
if (err) {
PyErr_SetString(PyExc_KeyError, sid);
return (NULL);
}
if (isuser) {
err = idmap_getwinnamebyuid(id,
IDMAP_REQ_FLG_USE_CACHE, &name, &domain);
} else {
err = idmap_getwinnamebygid(id,
IDMAP_REQ_FLG_USE_CACHE, &name, &domain);
}
if (err != IDMAP_SUCCESS) {
PyErr_SetString(PyExc_KeyError, sid);
return (NULL);
}
(void) snprintf(buf, sizeof (buf), "%s@%s", name, domain);
free(name);
free(domain);
return (Py_BuildValue("s", buf));
#else /* sun */
return(NULL);
#endif /* sun */
}
static PyObject *
py_isglobalzone(PyObject *self, PyObject *args)
{
return (Py_BuildValue("i", getzoneid() == GLOBAL_ZONEID));
}
static PyObject *
py_set_cmdstr(PyObject *self, PyObject *args)
{
@ -584,12 +522,7 @@ static PyMethodDef zfsmethods[] = {
"Get dataset properties."},
{"get_proptable", py_get_proptable, METH_NOARGS,
"Get property table."},
/* Below are not really zfs-specific: */
{"sid_to_id", py_sid_to_id, METH_VARARGS, "Map SID to UID/GID."},
{"sid_to_name", py_sid_to_name, METH_VARARGS,
"Map SID to name@domain."},
{"isglobalzone", py_isglobalzone, METH_NOARGS,
"Determine if this is the global zone."},
{"get_holds", py_get_holds, METH_VARARGS, "Get user holds."},
{NULL, NULL, 0, NULL}
};

View File

@ -0,0 +1,70 @@
#! /usr/bin/python2.6
#
# CDDL HEADER START
#
# 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]
#
# CDDL HEADER END
#
# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
#
import zfs.util
class Table:
__slots__ = "fields", "rjustfields", "maxfieldlen", "lines"
__repr__ = zfs.util.default_repr
def __init__(self, fields, rjustfields=()):
# XXX maybe have a defaults, too?
self.fields = fields
self.rjustfields = rjustfields
self.maxfieldlen = dict.fromkeys(fields, 0)
self.lines = list()
def __updatemax(self, k, v):
self.maxfieldlen[k] = max(self.maxfieldlen.get(k, None), v)
def addline(self, sortkey, values):
"""values is a dict from field name to value"""
va = list()
for f in self.fields:
v = str(values[f])
va.append(v)
self.__updatemax(f, len(v))
self.lines.append((sortkey, va))
def printme(self, headers=True):
if headers:
d = dict([(f, f.upper()) for f in self.fields])
self.addline(None, d)
self.lines.sort()
for (k, va) in self.lines:
line = str()
for i in range(len(self.fields)):
if not headers:
line += va[i]
line += "\t"
else:
if self.fields[i] in self.rjustfields:
fmt = "%*s "
else:
fmt = "%-*s "
mfl = self.maxfieldlen[self.fields[i]]
line += fmt % (mfl, va[i])
print(line)

View File

@ -1,4 +1,4 @@
#! /usr/bin/python2.4
#! /usr/bin/python2.6
#
# CDDL HEADER START
#
@ -19,8 +19,7 @@
#
# CDDL HEADER END
#
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
#
import zfs.allow

View File

@ -1,4 +1,4 @@
#! /usr/bin/python2.4
#! /usr/bin/python2.6
#
# CDDL HEADER START
#
@ -19,21 +19,22 @@
#
# CDDL HEADER END
#
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
#
"""This module implements the "zfs userspace" and "zfs groupspace" subcommands.
The only public interface is the zfs.userspace.do_userspace() function."""
import zfs.util
import zfs.ioctl
import zfs.dataset
import optparse
import sys
import pwd
import grp
import errno
import solaris.misc
import zfs.util
import zfs.ioctl
import zfs.dataset
import zfs.table
_ = zfs.util._
@ -58,9 +59,6 @@ def skiptype(options, prop):
return True
return False
def updatemax(d, k, v):
d[k] = max(d.get(k, None), v)
def new_entry(options, isgroup, domain, rid):
"""Return a dict("field": value) for this domain (string) + rid (int)"""
@ -70,9 +68,9 @@ def new_entry(options, isgroup, domain, rid):
idstr = "%u" % rid
(typename, mapfunc) = {
(1, 1): ("SMB Group", lambda id: zfs.ioctl.sid_to_name(id, 0)),
(1, 1): ("SMB Group", lambda id: solaris.misc.sid_to_name(id, 0)),
(1, 0): ("POSIX Group", lambda id: grp.getgrgid(int(id)).gr_name),
(0, 1): ("SMB User", lambda id: zfs.ioctl.sid_to_name(id, 1)),
(0, 1): ("SMB User", lambda id: solaris.misc.sid_to_name(id, 1)),
(0, 0): ("POSIX User", lambda id: pwd.getpwuid(int(id)).pw_name)
}[isgroup, bool(domain)]
@ -102,8 +100,8 @@ def new_entry(options, isgroup, domain, rid):
v["quota.sort"] = 0
return v
def process_one_raw(acct, maxfieldlen, options, prop, elem):
"""Update the acct and maxfieldlen dicts to incorporate the
def process_one_raw(acct, options, prop, elem):
"""Update the acct dict to incorporate the
information from this elem from Dataset.userspace(prop)."""
(domain, rid, value) = elem
@ -111,7 +109,7 @@ def process_one_raw(acct, maxfieldlen, options, prop, elem):
if options.translate and domain:
try:
rid = zfs.ioctl.sid_to_id("%s-%u" % (domain, rid),
rid = solaris.misc.sid_to_id("%s-%u" % (domain, rid),
not isgroup)
domain = None
except KeyError:
@ -134,10 +132,6 @@ def process_one_raw(acct, maxfieldlen, options, prop, elem):
v[field] = str(value)
else:
v[field] = zfs.util.nicenum(value)
for k in v.keys():
# some of the .sort fields are integers, so have no len()
if isinstance(v[k], str):
updatemax(maxfieldlen, k, len(v[k]))
def do_userspace():
"""Implements the "zfs userspace" and "zfs groupspace" subcommands."""
@ -156,7 +150,7 @@ def usage(msg=None):
defaulttypes = "posixgroup,smbgroup"
fields = ("type", "name", "used", "quota")
ljustfields = ("type", "name")
rjustfields = ("used", "quota")
types = ("all", "posixuser", "smbuser", "posixgroup", "smbgroup")
u = _("%s [-niHp] [-o field[,...]] [-sS field] ... \n") % sys.argv[1]
@ -209,38 +203,23 @@ def usage(msg=None):
ds = zfs.dataset.Dataset(dsname, types=("filesystem"))
if ds.getprop("jailed") and zfs.ioctl.isglobalzone():
if ds.getprop("jailed") and solaris.misc.isglobalzone():
options.noname = True
if not ds.getprop("useraccounting"):
print(_("Initializing accounting information on old filesystem, please wait..."))
ds.userspace_upgrade()
acct = dict()
maxfieldlen = dict()
# gather and process accounting information
# Due to -i, we need to keep a dict, so we can potentially add
# together the posix ID and SID's usage. Grr.
acct = dict()
for prop in props.keys():
if skiptype(options, prop):
continue;
for elem in ds.userspace(prop):
process_one_raw(acct, maxfieldlen, options, prop, elem)
process_one_raw(acct, options, prop, elem)
# print out headers
if not options.noheaders:
line = str()
for field in options.fields:
# make sure the field header will fit
updatemax(maxfieldlen, field, len(field))
if field in ljustfields:
fmt = "%-*s "
else:
fmt = "%*s "
line += fmt % (maxfieldlen[field], field.upper())
print(line)
# custom sorting func
def cmpkey(val):
l = list()
for (opt, field) in options.sortfields:
@ -261,17 +240,7 @@ def cmpkey(val):
l.append(n)
return l
# print out data lines
for val in sorted(acct.itervalues(), key=cmpkey):
line = str()
for field in options.fields:
if options.noheaders:
line += val[field]
line += "\t"
else:
if field in ljustfields:
fmt = "%-*s "
else:
fmt = "%*s "
line += fmt % (maxfieldlen[field], val[field])
print(line)
t = zfs.table.Table(options.fields, rjustfields)
for val in acct.itervalues():
t.addline(cmpkey(val), val)
t.printme(not options.noheaders)

View File

@ -1,4 +1,4 @@
#! /usr/bin/python2.4
#! /usr/bin/python2.6
#
# CDDL HEADER START
#
@ -19,8 +19,7 @@
#
# CDDL HEADER END
#
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
#
"""This module provides utility functions for ZFS.
@ -29,6 +28,7 @@
import gettext
import errno
import os
import solaris.misc
# Note: this module (zfs.util) should not import zfs.ioctl, because that
# would introduce a circular dependency
@ -37,8 +37,11 @@
dev = open("/dev/zfs", "w")
_ = gettext.translation("SUNW_OST_OSLIB", "/usr/lib/locale",
fallback=True).gettext
try:
_ = gettext.translation("SUNW_OST_OSLIB", "/usr/lib/locale",
fallback=True).gettext
except:
_ = solaris.misc.gettext
def default_repr(self):
"""A simple __repr__ function."""

View File

@ -6,8 +6,8 @@
.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzfs/common
LIB= zfs
DPADD= ${LIBUTIL}
LDADD= -lutil
DPADD= ${LIBMD} ${LIBPTHREAD} ${LIBUMEM} ${LIBUTIL}
LDADD= -lmd -lpthread -lumem -lutil
SRCS= deviceid.c \
fsshare.c \
@ -16,23 +16,28 @@ SRCS= deviceid.c \
zmount.c \
zone.c
SRCS+= zfs_deleg.c \
SRCS+= libzfs_changelist.c \
libzfs_config.c \
libzfs_dataset.c \
libzfs_diff.c \
libzfs_graph.c \
libzfs_import.c \
libzfs_mount.c \
libzfs_pool.c \
libzfs_sendrecv.c \
libzfs_status.c \
libzfs_util.c \
zfs_comutil.c \
zfs_deleg.c \
zfs_fletcher.c \
zfs_ioctl_compat.c \
zfs_namecheck.c \
zfs_prop.c \
zpool_prop.c \
zprop_common.c \
libzfs_dataset.c \
libzfs_util.c \
libzfs_graph.c \
libzfs_mount.c \
libzfs_pool.c \
libzfs_changelist.c \
libzfs_config.c \
libzfs_import.c \
libzfs_sendrecv.c \
libzfs_status.c
WARNS?= 0
CSTD= c99
CFLAGS+= -DZFS_NO_ACL
CFLAGS+= -I${.CURDIR}/../../../sbin/mount
CFLAGS+= -I${.CURDIR}/../../../cddl/lib/libumem

View File

@ -11,7 +11,7 @@
# LIST_SRCS
.PATH: ${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/os
# ATOMIC_SRCS
.if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "ia64" || ${MACHINE_ARCH} == "sparc64" || ${MACHINE_ARCH} == "powerpc64"
.if exists(${.CURDIR}/../../../sys/cddl/contrib/opensolaris/common/atomic/${MACHINE_ARCH}/opensolaris_atomic.S)
.PATH: ${.CURDIR}/../../../sys/cddl/contrib/opensolaris/common/atomic/${MACHINE_ARCH}
ATOMIC_SRCS= opensolaris_atomic.S
.if ${MACHINE_ARCH} != "ia64" && ${MACHINE_ARCH} != "sparc64"
@ -38,16 +38,16 @@ SRCS= ${ZFS_COMMON_SRCS} ${ZFS_SHARED_SRCS} \
WARNS?= 0
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris
CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/include
CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/lib/libumem
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzpool/common
CFLAGS+= -I${.CURDIR}/../../compat/opensolaris/include
CFLAGS+= -I${.CURDIR}/../../compat/opensolaris/lib/libumem
CFLAGS+= -I${.CURDIR}/../../contrib/opensolaris/lib/libzpool/common
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/sys
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/fs/zfs
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/common/zfs
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/head
CFLAGS+= -I${.CURDIR}/../../../cddl/lib/libumem
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libnvpair
CFLAGS+= -I${.CURDIR}/../../contrib/opensolaris/head
CFLAGS+= -I${.CURDIR}/../../lib/libumem
CFLAGS+= -I${.CURDIR}/../../contrib/opensolaris/lib/libnvpair
# XXX: pthread doesn't have mutex_owned() equivalent, so we need to look
# into libthr private structures. That's sooo evil, but it's only for
# ZFS debugging tools needs.
@ -56,8 +56,8 @@ CFLAGS+= -I${.CURDIR}/../../../lib/libpthread/thread
CFLAGS+= -I${.CURDIR}/../../../lib/libpthread/sys
CFLAGS+= -I${.CURDIR}/../../../lib/libthr/arch/${MACHINE_CPUARCH}/include
DPADD= ${LIBPTHREAD} ${LIBZ}
LDADD= -lpthread -lz
DPADD= ${LIBMD} ${LIBPTHREAD} ${LIBZ}
LDADD= -lmd -lpthread -lz
# atomic.S doesn't like profiling.
NO_PROFILE=

View File

@ -19,10 +19,10 @@ CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libnvpair
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/fs/zfs
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/sys
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/common/zfs
DPADD= ${LIBZFS} ${LIBGEOM} ${LIBBSDXML} ${LIBSBUF} \
${LIBM} ${LIBNVPAIR} ${LIBUUTIL} ${LIBUTIL}
LDADD= -lzfs -lgeom -lbsdxml -lsbuf \
-lm -lnvpair -luutil -lutil
DPADD= ${LIBBSDXML} ${LIBGEOM} ${LIBM} ${LIBNVPAIR} ${LIBSBUF} ${LIBUMEM} \
${LIBUTIL} ${LIBUUTIL} ${LIBZFS}
LDADD= -lbsdxml -lgeom -lm -lnvpair -lsbuf -lumem -lutil -luutil -lzfs
.include <bsd.prog.mk>

View File

@ -1,11 +1,13 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/cmd/zpool \
${.CURDIR}/../../../sys/cddl/contrib/opensolaris/common/zfs
.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/cmd/zpool
.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/cmd/stat/common
.PATH: ${.CURDIR}/../../../sys/cddl/contrib/opensolaris/common/zfs
PROG= zpool
MAN= zpool.8
SRCS= zpool_main.c zpool_vdev.c zpool_iter.c zpool_util.c zfs_comutil.c
SRCS+= timestamp.c
WARNS?= 0
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzpool/common
@ -21,10 +23,11 @@ CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/common/zfs
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/fs/zfs
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/sys
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzpool/common
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/cmd/stat/common
DPADD= ${LIBAVL} ${LIBZFS} ${LIBGEOM} ${LIBBSDXML} ${LIBSBUF} \
${LIBM} ${LIBNVPAIR} ${LIBUUTIL} ${LIBUTIL}
LDADD= -lavl -lzfs -lgeom -lbsdxml -lsbuf \
-lm -lnvpair -luutil -lutil
DPADD= ${LIBAVL} ${LIBBSDXML} ${LIBGEOM} ${LIBM} ${LIBNVPAIR} ${LIBSBUF} \
${LIBUMEM} ${LIBUTIL} ${LIBUUTIL} ${LIBZFS}
LDADD= -lavl -lbsdxml -lgeom -lm -lnvpair -lsbuf -lumem -lutil -luutil -lzfs
.include <bsd.prog.mk>

View File

@ -8,12 +8,16 @@ SUBDIR= \
ctfmerge \
sgsmsg \
${_zinject} \
${_zlook} \
${_zstreamdump} \
${_ztest}
.if ${MK_ZFS} != "no"
_zinject= zinject
#_zlook= zlook
.if ${MK_LIBTHR} != "no"
_ztest= ztest
_zstreamdump = zstreamdump
.endif
.endif

View File

@ -0,0 +1,25 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../contrib/opensolaris/cmd/zlook
PROG= zlook
NO_MAN=
WARNS?= 0
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris
#CFLAGS+= -I${.CURDIR}/../../compat/opensolaris/include
#CFLAGS+= -I${.CURDIR}/../../compat/opensolaris/lib/libumem
#CFLAGS+= -I${.CURDIR}/../../contrib/opensolaris/lib/libzfs/common
#CFLAGS+= -I${.CURDIR}/../../contrib/opensolaris/lib/libzpool/common
#CFLAGS+= -I${.CURDIR}/../../contrib/opensolaris/lib/libnvpair
#CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/fs/zfs
#CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/sys
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common
#CFLAGS+= -I${.CURDIR}/../../contrib/opensolaris/head
#CFLAGS+= -I${.CURDIR}/../../lib/libumem
#
#DPADD= ${LIBAVL} ${LIBGEOM} ${LIBM} ${LIBNVPAIR} ${LIBUMEM} ${LIBUUTIL} \
# ${LIBZFS} ${LIBZPOOL}
#LDADD= -lavl -lgeom -lm -lnvpair -lumem -luutil -lzfs -lzpool
.include <bsd.prog.mk>

View File

@ -0,0 +1,27 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../..//contrib/opensolaris/cmd/zstreamdump
PROG= zstreamdump
MAN= zstreamdump.1
WARNS?= 0
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris
CFLAGS+= -I${.CURDIR}/../../compat/opensolaris/include
CFLAGS+= -I${.CURDIR}/../../compat/opensolaris/lib/libumem
CFLAGS+= -I${.CURDIR}/../../contrib/opensolaris/lib/libzpool/common
CFLAGS+= -I${.CURDIR}/../../contrib/opensolaris/lib/libnvpair
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/common/zfs
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/fs/zfs
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/sys
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common
CFLAGS+= -I${.CURDIR}/../../contrib/opensolaris/head
CFLAGS+= -I${.CURDIR}/../../lib/libumem
DPADD= ${LIBM} ${LIBNVPAIR} ${LIBUMEM} ${LIBZPOOL} \
${LIBPTHREAD} ${LIBZ} ${LIBAVL}
LDADD= -lm -lnvpair -lumem -lzpool -lpthread -lz -lavl
CSTD= c99
.include <bsd.prog.mk>

View File

@ -10,6 +10,7 @@ CFLAGS+= -I${.CURDIR}/../../../sys/cddl/compat/opensolaris
CFLAGS+= -I${.CURDIR}/../../compat/opensolaris/include
CFLAGS+= -I${.CURDIR}/../../compat/opensolaris/lib/libumem
CFLAGS+= -I${.CURDIR}/../../contrib/opensolaris/lib/libzpool/common
CFLAGS+= -I${.CURDIR}/../../contrib/opensolaris/lib/libnvpair
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/fs/zfs
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/sys
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common

View File

@ -19,6 +19,7 @@ CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libzpool/common
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/fs/zfs
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/uts/common/sys
CFLAGS+= -I${.CURDIR}/../../../sys/cddl/contrib/opensolaris/common/zfs
CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/head
CFLAGS+= -I${.CURDIR}/../../lib/libumem

View File

@ -123,7 +123,7 @@ CRUNCH_LIBS+= -lalias -lcam -lcurses -ldevstat -lipsec
CRUNCH_LIBS+= -lipx
.endif
.if ${MK_ZFS} != "no"
CRUNCH_LIBS+= -lzfs -lnvpair -luutil -lavl
CRUNCH_LIBS+= -lavl -lnvpair -lpthread -lzfs -luutil -lumem
.endif
CRUNCH_LIBS+= -lgeom -lbsdxml -ljail -lkiconv -lmd -lreadline -lsbuf -lufs -lz

View File

@ -33,6 +33,7 @@ CFLAGS= -DBOOTPROG=\"gptzfsboot\" \
-I${.CURDIR}/../../../cddl/boot/zfs \
-I${.CURDIR}/../btx/lib -I. \
-I${.CURDIR}/../boot2 \
-I${.CURDIR}/../../.. \
-Wall -Waggregate-return -Wbad-function-cast -Wcast-align \
-Wmissing-declarations -Wmissing-prototypes -Wnested-externs \
-Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \

View File

@ -69,7 +69,7 @@ CLEANFILES+= zfsboot2 zfsboot.ld zfsboot.ldr zfsboot.bin zfsboot.out \
# We currently allow 32768 bytes for zfsboot - in practice it could be
# any size up to 3.5Mb but keeping it fixed size simplifies zfsldr.
#
BOOT2SIZE= 32768
BOOT2SIZE= 65536
zfsboot2: zfsboot.ld
@set -- `ls -l zfsboot.ld`; x=$$((${BOOT2SIZE}-$$5)); \

View File

@ -144,13 +144,16 @@ zfs_read(struct open_file *f, void *start, size_t size, size_t *resid /* out */)
{
spa_t *spa = (spa_t *) f->f_devdata;
struct file *fp = (struct file *)f->f_fsdata;
const znode_phys_t *zp = (const znode_phys_t *) fp->f_dnode.dn_bonus;
struct stat sb;
size_t n;
int rc;
rc = zfs_stat(f, &sb);
if (rc)
return (rc);
n = size;
if (fp->f_seekp + n > zp->zp_size)
n = zp->zp_size - fp->f_seekp;
if (fp->f_seekp + n > sb.st_size)
n = sb.st_size - fp->f_seekp;
rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp, start, n);
if (rc)
@ -182,7 +185,6 @@ static off_t
zfs_seek(struct open_file *f, off_t offset, int where)
{
struct file *fp = (struct file *)f->f_fsdata;
znode_phys_t *zp = (znode_phys_t *) fp->f_dnode.dn_bonus;
switch (where) {
case SEEK_SET:
@ -192,8 +194,18 @@ zfs_seek(struct open_file *f, off_t offset, int where)
fp->f_seekp += offset;
break;
case SEEK_END:
fp->f_seekp = zp->zp_size - offset;
{
struct stat sb;
int error;
error = zfs_stat(f, &sb);
if (error != 0) {
errno = error;
return (-1);
}
fp->f_seekp = sb.st_size - offset;
break;
}
default:
errno = EINVAL;
return (-1);
@ -204,16 +216,10 @@ zfs_seek(struct open_file *f, off_t offset, int where)
static int
zfs_stat(struct open_file *f, struct stat *sb)
{
spa_t *spa = (spa_t *) f->f_devdata;
struct file *fp = (struct file *)f->f_fsdata;
znode_phys_t *zp = (znode_phys_t *) fp->f_dnode.dn_bonus;
/* only important stuff */
sb->st_mode = zp->zp_mode;
sb->st_uid = zp->zp_uid;
sb->st_gid = zp->zp_gid;
sb->st_size = zp->zp_size;
return (0);
return (zfs_dnode_stat(spa, &fp->f_dnode, sb));
}
static int
@ -221,14 +227,16 @@ zfs_readdir(struct open_file *f, struct dirent *d)
{
spa_t *spa = (spa_t *) f->f_devdata;
struct file *fp = (struct file *)f->f_fsdata;
znode_phys_t *zp = (znode_phys_t *) fp->f_dnode.dn_bonus;
mzap_ent_phys_t mze;
struct stat sb;
size_t bsize = fp->f_dnode.dn_datablkszsec << SPA_MINBLOCKSHIFT;
int rc;
if ((zp->zp_mode >> 12) != 0x4) {
rc = zfs_stat(f, &sb);
if (rc)
return (rc);
if (!S_ISDIR(sb.st_mode))
return (ENOTDIR);
}
/*
* If this is the first read, get the zap type.

View File

@ -31,6 +31,8 @@ __FBSDID("$FreeBSD$");
* Stand-alone ZFS file reader.
*/
#include <sys/stat.h>
#include "zfsimpl.h"
#include "zfssubr.c"
@ -70,26 +72,30 @@ zfs_init(void)
zfs_init_crc();
}
static char *
zfs_alloc_temp(size_t sz)
static void *
zfs_alloc(size_t size)
{
char *p;
char *ptr;
if (zfs_temp_ptr + sz > zfs_temp_end) {
if (zfs_temp_ptr + size > zfs_temp_end) {
printf("ZFS: out of temporary buffer space\n");
for (;;) ;
}
p = zfs_temp_ptr;
zfs_temp_ptr += sz;
ptr = zfs_temp_ptr;
zfs_temp_ptr += size;
return (p);
return (ptr);
}
static void
zfs_reset_temp(void)
zfs_free(void *ptr, size_t size)
{
zfs_temp_ptr = zfs_temp_buf;
zfs_temp_ptr -= size;
if (zfs_temp_ptr != ptr) {
printf("ZFS: zfs_alloc()/zfs_free() mismatch\n");
for (;;) ;
}
}
static int
@ -341,7 +347,7 @@ vdev_read_phys(vdev_t *vdev, const blkptr_t *bp, void *buf,
rc = vdev->v_phys_read(vdev, vdev->v_read_priv, offset, buf, psize);
if (rc)
return (rc);
if (bp && zio_checksum_error(bp, buf))
if (bp && zio_checksum_error(bp, buf, offset))
return (EIO);
return (0);
@ -428,7 +434,8 @@ vdev_create(uint64_t guid, vdev_read_t *read)
}
static int
vdev_init_from_nvlist(const unsigned char *nvlist, vdev_t **vdevp, int is_newer)
vdev_init_from_nvlist(const unsigned char *nvlist, vdev_t *pvdev,
vdev_t **vdevp, int is_newer)
{
int rc;
uint64_t guid, id, ashift, nparity;
@ -453,7 +460,7 @@ vdev_init_from_nvlist(const unsigned char *nvlist, vdev_t **vdevp, int is_newer)
&& strcmp(type, VDEV_TYPE_DISK)
&& strcmp(type, VDEV_TYPE_RAIDZ)
&& strcmp(type, VDEV_TYPE_REPLACING)) {
printf("ZFS: can only boot from disk, mirror or raidz vdevs\n");
printf("ZFS: can only boot from disk, mirror, raidz1, raidz2 and raidz3 vdevs\n");
return (EIO);
}
@ -484,6 +491,7 @@ vdev_init_from_nvlist(const unsigned char *nvlist, vdev_t **vdevp, int is_newer)
vdev = vdev_create(guid, vdev_disk_read);
vdev->v_id = id;
vdev->v_top = pvdev != NULL ? pvdev : vdev;
if (nvlist_find(nvlist, ZPOOL_CONFIG_ASHIFT,
DATA_TYPE_UINT64, 0, &ashift) == 0)
vdev->v_ashift = ashift;
@ -503,8 +511,14 @@ vdev_init_from_nvlist(const unsigned char *nvlist, vdev_t **vdevp, int is_newer)
if (!strcmp(type, "raidz")) {
if (vdev->v_nparity == 1)
vdev->v_name = "raidz1";
else
else if (vdev->v_nparity == 2)
vdev->v_name = "raidz2";
else if (vdev->v_nparity == 3)
vdev->v_name = "raidz3";
else {
printf("ZFS: can only boot from disk, mirror, raidz1, raidz2 and raidz3 vdevs\n");
return (EIO);
}
} else {
vdev->v_name = strdup(type);
}
@ -541,7 +555,7 @@ vdev_init_from_nvlist(const unsigned char *nvlist, vdev_t **vdevp, int is_newer)
if (rc == 0) {
vdev->v_nchildren = nkids;
for (i = 0; i < nkids; i++) {
rc = vdev_init_from_nvlist(kids, &kid, is_newer);
rc = vdev_init_from_nvlist(kids, vdev, &kid, is_newer);
if (rc)
return (rc);
if (is_new)
@ -770,7 +784,7 @@ vdev_probe(vdev_phys_read_t *read, void *read_priv, spa_t **spap)
const char *pool_name;
const unsigned char *vdevs;
int i, rc, is_newer;
char upbuf[1024];
char *upbuf;
const struct uberblock *up;
/*
@ -814,17 +828,10 @@ vdev_probe(vdev_phys_read_t *read, void *read_priv, spa_t **spap)
return (EIO);
}
#ifndef TEST
if (val != POOL_STATE_ACTIVE) {
/*
* Don't print a message here. If we happen to reboot
* while where is an exported pool around, we don't
* need a cascade of confusing messages during boot.
*/
/*printf("ZFS: pool is not active\n");*/
if (val == POOL_STATE_DESTROYED) {
/* We don't boot only from destroyed pools. */
return (EIO);
}
#endif
if (nvlist_find(nvlist,
ZPOOL_CONFIG_POOL_TXG,
@ -884,7 +891,7 @@ vdev_probe(vdev_phys_read_t *read, void *read_priv, spa_t **spap)
return (EIO);
}
rc = vdev_init_from_nvlist(vdevs, &top_vdev, is_newer);
rc = vdev_init_from_nvlist(vdevs, NULL, &top_vdev, is_newer);
if (rc)
return (rc);
@ -920,22 +927,23 @@ vdev_probe(vdev_phys_read_t *read, void *read_priv, spa_t **spap)
* the best uberblock and then we can actually access
* the contents of the pool.
*/
upbuf = zfs_alloc(VDEV_UBERBLOCK_SIZE(vdev));
up = (const struct uberblock *)upbuf;
for (i = 0;
i < VDEV_UBERBLOCK_RING >> UBERBLOCK_SHIFT;
i < VDEV_UBERBLOCK_COUNT(vdev);
i++) {
off = offsetof(vdev_label_t, vl_uberblock);
off += i << UBERBLOCK_SHIFT;
off = VDEV_UBERBLOCK_OFFSET(vdev, i);
BP_ZERO(&bp);
DVA_SET_OFFSET(&bp.blk_dva[0], off);
BP_SET_LSIZE(&bp, 1 << UBERBLOCK_SHIFT);
BP_SET_PSIZE(&bp, 1 << UBERBLOCK_SHIFT);
BP_SET_LSIZE(&bp, VDEV_UBERBLOCK_SIZE(vdev));
BP_SET_PSIZE(&bp, VDEV_UBERBLOCK_SIZE(vdev));
BP_SET_CHECKSUM(&bp, ZIO_CHECKSUM_LABEL);
BP_SET_COMPRESS(&bp, ZIO_COMPRESS_OFF);
ZIO_SET_CHECKSUM(&bp.blk_cksum, off, 0, 0, 0);
if (vdev_read_phys(vdev, &bp, upbuf, off, 0))
if (vdev_read_phys(vdev, NULL, upbuf, off, VDEV_UBERBLOCK_SIZE(vdev)))
continue;
up = (const struct uberblock *) upbuf;
if (up->ub_magic != UBERBLOCK_MAGIC)
continue;
if (up->ub_txg < spa->spa_txg)
@ -947,6 +955,7 @@ vdev_probe(vdev_phys_read_t *read, void *read_priv, spa_t **spap)
spa->spa_uberblock = *up;
}
}
zfs_free(upbuf, VDEV_UBERBLOCK_SIZE(vdev));
if (spap)
*spap = spa;
@ -1000,16 +1009,11 @@ static int
zio_read(spa_t *spa, const blkptr_t *bp, void *buf)
{
int cpfunc = BP_GET_COMPRESS(bp);
size_t lsize = BP_GET_LSIZE(bp);
size_t psize = BP_GET_PSIZE(bp);
uint64_t align, size;
void *pbuf;
int i;
int i, error;
zfs_reset_temp();
if (cpfunc != ZIO_COMPRESS_OFF)
pbuf = zfs_alloc_temp(psize);
else
pbuf = buf;
error = EIO;
for (i = 0; i < SPA_DVAS_PER_BP; i++) {
const dva_t *dva = &bp->blk_dva[i];
@ -1021,32 +1025,49 @@ zio_read(spa_t *spa, const blkptr_t *bp, void *buf)
continue;
if (DVA_GET_GANG(dva)) {
if (zio_read_gang(spa, bp, dva, buf))
error = zio_read_gang(spa, bp, dva, buf);
if (error != 0)
continue;
} else {
vdevid = DVA_GET_VDEV(dva);
offset = DVA_GET_OFFSET(dva);
STAILQ_FOREACH(vdev, &spa->spa_vdevs, v_childlink)
STAILQ_FOREACH(vdev, &spa->spa_vdevs, v_childlink) {
if (vdev->v_id == vdevid)
break;
if (!vdev || !vdev->v_read) {
continue;
}
if (vdev->v_read(vdev, bp, pbuf, offset, psize))
if (!vdev || !vdev->v_read)
continue;
if (cpfunc != ZIO_COMPRESS_OFF) {
if (zio_decompress_data(cpfunc, pbuf, psize,
buf, lsize))
return (EIO);
size = BP_GET_PSIZE(bp);
align = 1ULL << vdev->v_top->v_ashift;
if (P2PHASE(size, align) != 0)
size = P2ROUNDUP(size, align);
if (size != BP_GET_PSIZE(bp) || cpfunc != ZIO_COMPRESS_OFF)
pbuf = zfs_alloc(size);
else
pbuf = buf;
error = vdev->v_read(vdev, bp, pbuf, offset, size);
if (error == 0) {
if (cpfunc != ZIO_COMPRESS_OFF) {
error = zio_decompress_data(cpfunc,
pbuf, BP_GET_PSIZE(bp), buf,
BP_GET_LSIZE(bp));
} else if (size != BP_GET_PSIZE(bp)) {
bcopy(pbuf, buf, BP_GET_PSIZE(bp));
}
}
if (buf != pbuf)
zfs_free(pbuf, size);
if (error != 0)
continue;
}
return (0);
error = 0;
break;
}
printf("ZFS: i/o error - all block copies unavailable\n");
return (EIO);
if (error != 0)
printf("ZFS: i/o error - all block copies unavailable\n");
return (error);
}
static int
@ -1276,7 +1297,7 @@ zap_lookup(spa_t *spa, const dnode_phys_t *dnode, const char *name, uint64_t *va
{
int rc;
uint64_t zap_type;
size_t size = dnode->dn_datablkszsec * 512;
size_t size = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT;
rc = dnode_read(spa, dnode, 0, zap_scratch, size);
if (rc)
@ -1285,8 +1306,10 @@ zap_lookup(spa_t *spa, const dnode_phys_t *dnode, const char *name, uint64_t *va
zap_type = *(uint64_t *) zap_scratch;
if (zap_type == ZBT_MICRO)
return mzap_lookup(spa, dnode, name, value);
else
else if (zap_type == ZBT_HEADER)
return fzap_lookup(spa, dnode, name, value);
printf("ZFS: invalid zap_type=%d\n", (int)zap_type);
return (EIO);
}
#ifdef BOOT2
@ -1497,6 +1520,7 @@ zfs_mount_root(spa_t *spa, objset_phys_t *objset)
static int
zfs_mount_pool(spa_t *spa)
{
/*
* Find the MOS and work our way in from there.
*/
@ -1516,6 +1540,58 @@ zfs_mount_pool(spa_t *spa)
return (0);
}
static int
zfs_dnode_stat(spa_t *spa, dnode_phys_t *dn, struct stat *sb)
{
if (dn->dn_bonustype != DMU_OT_SA) {
znode_phys_t *zp = (znode_phys_t *)dn->dn_bonus;
sb->st_mode = zp->zp_mode;
sb->st_uid = zp->zp_uid;
sb->st_gid = zp->zp_gid;
sb->st_size = zp->zp_size;
} else {
sa_hdr_phys_t *sahdrp;
int hdrsize;
size_t size = 0;
void *buf = NULL;
if (dn->dn_bonuslen != 0)
sahdrp = (sa_hdr_phys_t *)DN_BONUS(dn);
else {
if ((dn->dn_flags & DNODE_FLAG_SPILL_BLKPTR) != 0) {
blkptr_t *bp = &dn->dn_spill;
int error;
size = BP_GET_LSIZE(bp);
buf = zfs_alloc(size);
error = zio_read(spa, bp, buf);
if (error != 0) {
zfs_free(buf, size);
return (error);
}
sahdrp = buf;
} else {
return (EIO);
}
}
hdrsize = SA_HDR_SIZE(sahdrp);
sb->st_mode = *(uint64_t *)((char *)sahdrp + hdrsize +
SA_MODE_OFFSET);
sb->st_uid = *(uint64_t *)((char *)sahdrp + hdrsize +
SA_UID_OFFSET);
sb->st_gid = *(uint64_t *)((char *)sahdrp + hdrsize +
SA_GID_OFFSET);
sb->st_size = *(uint64_t *)((char *)sahdrp + hdrsize +
SA_SIZE_OFFSET);
if (buf != NULL)
zfs_free(buf, size);
}
return (0);
}
/*
* Lookup a file and return its dnode.
*/
@ -1525,11 +1601,11 @@ zfs_lookup(spa_t *spa, const char *upath, dnode_phys_t *dnode)
int rc;
uint64_t objnum, rootnum, parentnum;
dnode_phys_t dn;
const znode_phys_t *zp = (const znode_phys_t *) dn.dn_bonus;
const char *p, *q;
char element[256];
char path[1024];
int symlinks_followed = 0;
struct stat sb;
if (spa->spa_root_objset.os_type != DMU_OST_ZFS) {
printf("ZFS: unexpected object set type %llu\n",
@ -1569,9 +1645,11 @@ zfs_lookup(spa_t *spa, const char *upath, dnode_phys_t *dnode)
p = 0;
}
if ((zp->zp_mode >> 12) != 0x4) {
rc = zfs_dnode_stat(spa, &dn, &sb);
if (rc)
return (rc);
if (!S_ISDIR(sb.st_mode))
return (ENOTDIR);
}
parentnum = objnum;
rc = zap_lookup(spa, &dn, element, &objnum);
@ -1586,7 +1664,10 @@ zfs_lookup(spa_t *spa, const char *upath, dnode_phys_t *dnode)
/*
* Check for symlink.
*/
if ((zp->zp_mode >> 12) == 0xa) {
rc = zfs_dnode_stat(spa, &dn, &sb);
if (rc)
return (rc);
if (S_ISLNK(sb.st_mode)) {
if (symlinks_followed > 10)
return (EMLINK);
symlinks_followed++;
@ -1596,14 +1677,14 @@ zfs_lookup(spa_t *spa, const char *upath, dnode_phys_t *dnode)
* current path onto the end.
*/
if (p)
strcpy(&path[zp->zp_size], p);
strcpy(&path[sb.st_size], p);
else
path[zp->zp_size] = 0;
if (zp->zp_size + sizeof(znode_phys_t) <= dn.dn_bonuslen) {
path[sb.st_size] = 0;
if (sb.st_size + sizeof(znode_phys_t) <= dn.dn_bonuslen) {
memcpy(path, &dn.dn_bonus[sizeof(znode_phys_t)],
zp->zp_size);
sb.st_size);
} else {
rc = dnode_read(spa, &dn, 0, path, zp->zp_size);
rc = dnode_read(spa, &dn, 0, path, sb.st_size);
if (rc)
return (rc);
}

View File

@ -42,6 +42,23 @@ fletcher_2_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
ZIO_SET_CHECKSUM(zcp, a0, a1, b0, b1);
}
static void
fletcher_2_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp)
{
const uint64_t *ip = buf;
const uint64_t *ipend = ip + (size / sizeof (uint64_t));
uint64_t a0, b0, a1, b1;
for (a0 = b0 = a1 = b1 = 0; ip < ipend; ip += 2) {
a0 += BSWAP_64(ip[0]);
a1 += BSWAP_64(ip[1]);
b0 += a0;
b1 += a1;
}
ZIO_SET_CHECKSUM(zcp, a0, a1, b0, b1);
}
static void
fletcher_4_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
{
@ -58,3 +75,20 @@ fletcher_4_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
ZIO_SET_CHECKSUM(zcp, a, b, c, d);
}
static void
fletcher_4_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp)
{
const uint32_t *ip = buf;
const uint32_t *ipend = ip + (size / sizeof (uint32_t));
uint64_t a, b, c, d;
for (a = b = c = d = 0; ip < ipend; ip++) {
a += BSWAP_32(ip[0]);
b += a;
c += b;
d += c;
}
ZIO_SET_CHECKSUM(zcp, a, b, c, d);
}

View File

@ -94,6 +94,14 @@
#define BF64_SET_SB(x, low, len, shift, bias, val) \
BF64_SET(x, low, len, ((val) >> (shift)) - (bias))
/*
* Macros to reverse byte order
*/
#define BSWAP_8(x) ((x) & 0xff)
#define BSWAP_16(x) ((BSWAP_8(x) << 8) | BSWAP_8((x) >> 8))
#define BSWAP_32(x) ((BSWAP_16(x) << 16) | BSWAP_16((x) >> 16))
#define BSWAP_64(x) ((BSWAP_32(x) << 32) | BSWAP_32((x) >> 32))
/*
* We currently support nine block sizes, from 512 bytes to 128K.
* We could go higher, but the benefits are near-zero and the cost
@ -150,15 +158,15 @@ typedef struct zio_cksum {
* +-------+-------+-------+-------+-------+-------+-------+-------+
* 5 |G| offset3 |
* +-------+-------+-------+-------+-------+-------+-------+-------+
* 6 |E| lvl | type | cksum | comp | PSIZE | LSIZE |
* 6 |BDX|lvl| type | cksum | comp | PSIZE | LSIZE |
* +-------+-------+-------+-------+-------+-------+-------+-------+
* 7 | padding |
* +-------+-------+-------+-------+-------+-------+-------+-------+
* 8 | padding |
* +-------+-------+-------+-------+-------+-------+-------+-------+
* 9 | padding |
* 9 | physical birth txg |
* +-------+-------+-------+-------+-------+-------+-------+-------+
* a | birth txg |
* a | logical birth txg |
* +-------+-------+-------+-------+-------+-------+-------+-------+
* b | fill count |
* +-------+-------+-------+-------+-------+-------+-------+-------+
@ -182,25 +190,29 @@ typedef struct zio_cksum {
* cksum checksum function
* comp compression function
* G gang block indicator
* E endianness
* type DMU object type
* B byteorder (endianness)
* D dedup
* X unused
* lvl level of indirection
* birth txg transaction group in which the block was born
* type DMU object type
* phys birth txg of block allocation; zero if same as logical birth txg
* log. birth transaction group in which the block was logically born
* fill count number of non-zero blocks under this bp
* checksum[4] 256-bit checksum of the data this bp describes
*/
typedef struct blkptr {
dva_t blk_dva[3]; /* 128-bit Data Virtual Address */
uint64_t blk_prop; /* size, compression, type, etc */
uint64_t blk_pad[3]; /* Extra space for the future */
uint64_t blk_birth; /* transaction group at birth */
uint64_t blk_fill; /* fill count */
zio_cksum_t blk_cksum; /* 256-bit checksum */
} blkptr_t;
#define SPA_BLKPTRSHIFT 7 /* blkptr_t is 128 bytes */
#define SPA_DVAS_PER_BP 3 /* Number of DVAs in a bp */
typedef struct blkptr {
dva_t blk_dva[SPA_DVAS_PER_BP]; /* Data Virtual Addresses */
uint64_t blk_prop; /* size, compression, type, etc */
uint64_t blk_pad[2]; /* Extra space for the future */
uint64_t blk_phys_birth; /* txg when block was allocated */
uint64_t blk_birth; /* transaction group at birth */
uint64_t blk_fill; /* fill count */
zio_cksum_t blk_cksum; /* 256-bit checksum */
} blkptr_t;
/*
* Macros to get and set fields in a bp or DVA.
*/
@ -246,9 +258,15 @@ typedef struct blkptr {
#define BP_GET_LEVEL(bp) BF64_GET((bp)->blk_prop, 56, 5)
#define BP_SET_LEVEL(bp, x) BF64_SET((bp)->blk_prop, 56, 5, x)
#define BP_GET_DEDUP(bp) BF64_GET((bp)->blk_prop, 62, 1)
#define BP_SET_DEDUP(bp, x) BF64_SET((bp)->blk_prop, 62, 1, x)
#define BP_GET_BYTEORDER(bp) (0 - BF64_GET((bp)->blk_prop, 63, 1))
#define BP_SET_BYTEORDER(bp, x) BF64_SET((bp)->blk_prop, 63, 1, x)
#define BP_PHYSICAL_BIRTH(bp) \
((bp)->blk_phys_birth ? (bp)->blk_phys_birth : (bp)->blk_birth)
#define BP_GET_ASIZE(bp) \
(DVA_GET_ASIZE(&(bp)->blk_dva[0]) + DVA_GET_ASIZE(&(bp)->blk_dva[1]) + \
DVA_GET_ASIZE(&(bp)->blk_dva[2]))
@ -304,18 +322,41 @@ typedef struct blkptr {
(bp)->blk_prop = 0; \
(bp)->blk_pad[0] = 0; \
(bp)->blk_pad[1] = 0; \
(bp)->blk_pad[2] = 0; \
(bp)->blk_phys_birth = 0; \
(bp)->blk_birth = 0; \
(bp)->blk_fill = 0; \
ZIO_SET_CHECKSUM(&(bp)->blk_cksum, 0, 0, 0, 0); \
}
#define ZBT_MAGIC 0x210da7ab10c7a11ULL /* zio data bloc tail */
/*
* Embedded checksum
*/
#define ZEC_MAGIC 0x210da7ab10c7a11ULL
typedef struct zio_block_tail {
uint64_t zbt_magic; /* for validation, endianness */
zio_cksum_t zbt_cksum; /* 256-bit checksum */
} zio_block_tail_t;
typedef struct zio_eck {
uint64_t zec_magic; /* for validation, endianness */
zio_cksum_t zec_cksum; /* 256-bit checksum */
} zio_eck_t;
/*
* Gang block headers are self-checksumming and contain an array
* of block pointers.
*/
#define SPA_GANGBLOCKSIZE SPA_MINBLOCKSIZE
#define SPA_GBH_NBLKPTRS ((SPA_GANGBLOCKSIZE - \
sizeof (zio_eck_t)) / sizeof (blkptr_t))
#define SPA_GBH_FILLER ((SPA_GANGBLOCKSIZE - \
sizeof (zio_eck_t) - \
(SPA_GBH_NBLKPTRS * sizeof (blkptr_t))) /\
sizeof (uint64_t))
typedef struct zio_gbh {
blkptr_t zg_blkptr[SPA_GBH_NBLKPTRS];
uint64_t zg_filler[SPA_GBH_FILLER];
zio_eck_t zg_tail;
} zio_gbh_phys_t;
#define VDEV_RAIDZ_MAXPARITY 3
#define VDEV_PAD_SIZE (8 << 10)
/* 2 padding areas (vl_pad1 and vl_pad2) to skip */
@ -324,7 +365,7 @@ typedef struct zio_block_tail {
#define VDEV_UBERBLOCK_RING (128 << 10)
#define VDEV_UBERBLOCK_SHIFT(vd) \
MAX((vd)->vdev_top->vdev_ashift, UBERBLOCK_SHIFT)
MAX((vd)->v_top->v_ashift, UBERBLOCK_SHIFT)
#define VDEV_UBERBLOCK_COUNT(vd) \
(VDEV_UBERBLOCK_RING >> VDEV_UBERBLOCK_SHIFT(vd))
#define VDEV_UBERBLOCK_OFFSET(vd, n) \
@ -332,8 +373,8 @@ typedef struct zio_block_tail {
#define VDEV_UBERBLOCK_SIZE(vd) (1ULL << VDEV_UBERBLOCK_SHIFT(vd))
typedef struct vdev_phys {
char vp_nvlist[VDEV_PHYS_SIZE - sizeof (zio_block_tail_t)];
zio_block_tail_t vp_zbt;
char vp_nvlist[VDEV_PHYS_SIZE - sizeof (zio_eck_t)];
zio_eck_t vp_zbt;
} vdev_phys_t;
typedef struct vdev_label {
@ -363,24 +404,6 @@ typedef struct vdev_label {
#define VDEV_LABEL_END_SIZE (2 * sizeof (vdev_label_t))
#define VDEV_LABELS 4
/*
* Gang block headers are self-checksumming and contain an array
* of block pointers.
*/
#define SPA_GANGBLOCKSIZE SPA_MINBLOCKSIZE
#define SPA_GBH_NBLKPTRS ((SPA_GANGBLOCKSIZE - \
sizeof (zio_block_tail_t)) / sizeof (blkptr_t))
#define SPA_GBH_FILLER ((SPA_GANGBLOCKSIZE - \
sizeof (zio_block_tail_t) - \
(SPA_GBH_NBLKPTRS * sizeof (blkptr_t))) /\
sizeof (uint64_t))
typedef struct zio_gbh {
blkptr_t zg_blkptr[SPA_GBH_NBLKPTRS];
uint64_t zg_filler[SPA_GBH_FILLER];
zio_block_tail_t zg_tail;
} zio_gbh_phys_t;
enum zio_checksum {
ZIO_CHECKSUM_INHERIT = 0,
ZIO_CHECKSUM_ON,
@ -391,10 +414,11 @@ enum zio_checksum {
ZIO_CHECKSUM_FLETCHER_2,
ZIO_CHECKSUM_FLETCHER_4,
ZIO_CHECKSUM_SHA256,
ZIO_CHECKSUM_ZILOG2,
ZIO_CHECKSUM_FUNCTIONS
};
#define ZIO_CHECKSUM_ON_VALUE ZIO_CHECKSUM_FLETCHER_2
#define ZIO_CHECKSUM_ON_VALUE ZIO_CHECKSUM_FLETCHER_4
#define ZIO_CHECKSUM_DEFAULT ZIO_CHECKSUM_ON
enum zio_compress {
@ -412,6 +436,7 @@ enum zio_compress {
ZIO_COMPRESS_GZIP_7,
ZIO_COMPRESS_GZIP_8,
ZIO_COMPRESS_GZIP_9,
ZIO_COMPRESS_ZLE,
ZIO_COMPRESS_FUNCTIONS
};
@ -470,13 +495,28 @@ typedef enum {
#define SPA_VERSION_13 13ULL
#define SPA_VERSION_14 14ULL
#define SPA_VERSION_15 15ULL
#define SPA_VERSION_16 16ULL
#define SPA_VERSION_17 17ULL
#define SPA_VERSION_18 18ULL
#define SPA_VERSION_19 19ULL
#define SPA_VERSION_20 20ULL
#define SPA_VERSION_21 21ULL
#define SPA_VERSION_22 22ULL
#define SPA_VERSION_23 23ULL
#define SPA_VERSION_24 24ULL
#define SPA_VERSION_25 25ULL
#define SPA_VERSION_26 26ULL
#define SPA_VERSION_27 27ULL
#define SPA_VERSION_28 28ULL
/*
* When bumping up SPA_VERSION, make sure GRUB ZFS understand the on-disk
* format change. Go to usr/src/grub/grub-0.95/stage2/{zfs-include/, fsys_zfs*},
* and do the appropriate changes.
* When bumping up SPA_VERSION, make sure GRUB ZFS understands the on-disk
* format change. Go to usr/src/grub/grub-0.97/stage2/{zfs-include/, fsys_zfs*},
* and do the appropriate changes. Also bump the version number in
* usr/src/grub/capability.
*/
#define SPA_VERSION SPA_VERSION_15
#define SPA_VERSION_STRING "15"
#define SPA_VERSION SPA_VERSION_28
#define SPA_VERSION_STRING "28"
/*
* Symbolic names for the changes that caused a SPA_VERSION switch.
@ -513,6 +553,20 @@ typedef enum {
#define SPA_VERSION_USED_BREAKDOWN SPA_VERSION_13
#define SPA_VERSION_PASSTHROUGH_X SPA_VERSION_14
#define SPA_VERSION_USERSPACE SPA_VERSION_15
#define SPA_VERSION_STMF_PROP SPA_VERSION_16
#define SPA_VERSION_RAIDZ3 SPA_VERSION_17
#define SPA_VERSION_USERREFS SPA_VERSION_18
#define SPA_VERSION_HOLES SPA_VERSION_19
#define SPA_VERSION_ZLE_COMPRESSION SPA_VERSION_20
#define SPA_VERSION_DEDUP SPA_VERSION_21
#define SPA_VERSION_RECVD_PROPS SPA_VERSION_22
#define SPA_VERSION_SLIM_ZIL SPA_VERSION_23
#define SPA_VERSION_SA SPA_VERSION_24
#define SPA_VERSION_SCAN SPA_VERSION_25
#define SPA_VERSION_DIR_CLONES SPA_VERSION_26
#define SPA_VERSION_DEADLISTS SPA_VERSION_26
#define SPA_VERSION_FAST_SNAP SPA_VERSION_27
#define SPA_VERSION_MULTI_REPLACE SPA_VERSION_28
/*
* The following are configuration names used in the nvlist describing a pool's
@ -558,6 +612,8 @@ typedef enum {
#define ZPOOL_CONFIG_FAULTED "faulted"
#define ZPOOL_CONFIG_DEGRADED "degraded"
#define ZPOOL_CONFIG_REMOVED "removed"
#define ZPOOL_CONFIG_FRU "fru"
#define ZPOOL_CONFIG_AUX_STATE "aux_state"
#define VDEV_TYPE_ROOT "root"
#define VDEV_TYPE_MIRROR "mirror"
@ -566,7 +622,10 @@ typedef enum {
#define VDEV_TYPE_DISK "disk"
#define VDEV_TYPE_FILE "file"
#define VDEV_TYPE_MISSING "missing"
#define VDEV_TYPE_HOLE "hole"
#define VDEV_TYPE_SPARE "spare"
#define VDEV_TYPE_LOG "log"
#define VDEV_TYPE_L2CACHE "l2cache"
/*
* This is needed in userland to report the minimum necessary device size.
@ -577,11 +636,7 @@ typedef enum {
* The location of the pool configuration repository, shared between kernel and
* userland.
*/
#define ZPOOL_CACHE_DIR "/boot/zfs"
#define ZPOOL_CACHE_FILE "zpool.cache"
#define ZPOOL_CACHE_TMP ".zpool.cache"
#define ZPOOL_CACHE ZPOOL_CACHE_DIR "/" ZPOOL_CACHE_FILE
#define ZPOOL_CACHE "/boot/zfs/zpool.cache"
/*
* vdev states are ordered from least to most healthy.
@ -694,7 +749,11 @@ struct uberblock {
#define EPB(blkshift, typeshift) (1 << (blkshift - typeshift))
/* Is dn_used in bytes? if not, it's in multiples of SPA_MINBLOCKSIZE */
#define DNODE_FLAG_USED_BYTES (1<<0)
#define DNODE_FLAG_USED_BYTES (1<<0)
#define DNODE_FLAG_USERUSED_ACCOUNTED (1<<1)
/* Does dnode have a SA spill blkptr in bonus? */
#define DNODE_FLAG_SPILL_BLKPTR (1<<2)
typedef struct dnode_phys {
uint8_t dn_type; /* dmu_object_type_t */
@ -716,7 +775,8 @@ typedef struct dnode_phys {
uint64_t dn_pad3[4];
blkptr_t dn_blkptr[1];
uint8_t dn_bonus[DN_MAX_BONUSLEN];
uint8_t dn_bonus[DN_MAX_BONUSLEN - sizeof (blkptr_t)];
blkptr_t dn_spill;
} dnode_phys_t;
typedef enum dmu_object_type {
@ -744,7 +804,7 @@ typedef enum dmu_object_type {
DMU_OT_DSL_DATASET, /* UINT64 */
/* zpl: */
DMU_OT_ZNODE, /* ZNODE */
DMU_OT_ACL, /* ACL */
DMU_OT_OLDACL, /* Old ACL */
DMU_OT_PLAIN_FILE_CONTENTS, /* UINT8 */
DMU_OT_DIRECTORY_CONTENTS, /* ZAP */
DMU_OT_MASTER_NODE, /* ZAP */
@ -761,7 +821,24 @@ typedef enum dmu_object_type {
DMU_OT_SPA_HISTORY, /* UINT8 */
DMU_OT_SPA_HISTORY_OFFSETS, /* spa_his_phys_t */
DMU_OT_POOL_PROPS, /* ZAP */
DMU_OT_DSL_PERMS, /* ZAP */
DMU_OT_ACL, /* ACL */
DMU_OT_SYSACL, /* SYSACL */
DMU_OT_FUID, /* FUID table (Packed NVLIST UINT8) */
DMU_OT_FUID_SIZE, /* FUID table size UINT64 */
DMU_OT_NEXT_CLONES, /* ZAP */
DMU_OT_SCAN_QUEUE, /* ZAP */
DMU_OT_USERGROUP_USED, /* ZAP */
DMU_OT_USERGROUP_QUOTA, /* ZAP */
DMU_OT_USERREFS, /* ZAP */
DMU_OT_DDT_ZAP, /* ZAP */
DMU_OT_DDT_STATS, /* ZAP */
DMU_OT_SA, /* System attr */
DMU_OT_SA_MASTER_NODE, /* ZAP */
DMU_OT_SA_ATTR_REGISTRATION, /* ZAP */
DMU_OT_SA_ATTR_LAYOUTS, /* ZAP */
DMU_OT_SCAN_XLATE, /* ZAP */
DMU_OT_DEDUP, /* fake dedup BP from ddt_bp_create() */
DMU_OT_NUMTYPES
} dmu_object_type_t;
@ -775,6 +852,54 @@ typedef enum dmu_objset_type {
DMU_OST_NUMTYPES
} dmu_objset_type_t;
/*
* header for all bonus and spill buffers.
* The header has a fixed portion with a variable number
* of "lengths" depending on the number of variable sized
* attribues which are determined by the "layout number"
*/
#define SA_MAGIC 0x2F505A /* ZFS SA */
typedef struct sa_hdr_phys {
uint32_t sa_magic;
uint16_t sa_layout_info; /* Encoded with hdrsize and layout number */
uint16_t sa_lengths[1]; /* optional sizes for variable length attrs */
/* ... Data follows the lengths. */
} sa_hdr_phys_t;
/*
* sa_hdr_phys -> sa_layout_info
*
* 16 10 0
* +--------+-------+
* | hdrsz |layout |
* +--------+-------+
*
* Bits 0-10 are the layout number
* Bits 11-16 are the size of the header.
* The hdrsize is the number * 8
*
* For example.
* hdrsz of 1 ==> 8 byte header
* 2 ==> 16 byte header
*
*/
#define SA_HDR_LAYOUT_NUM(hdr) BF32_GET(hdr->sa_layout_info, 0, 10)
#define SA_HDR_SIZE(hdr) BF32_GET_SB(hdr->sa_layout_info, 10, 16, 3, 0)
#define SA_HDR_LAYOUT_INFO_ENCODE(x, num, size) \
{ \
BF32_SET_SB(x, 10, 6, 3, 0, size); \
BF32_SET(x, 0, 10, num); \
}
#define SA_MODE_OFFSET 0
#define SA_SIZE_OFFSET 8
#define SA_GEN_OFFSET 16
#define SA_UID_OFFSET 24
#define SA_GID_OFFSET 32
#define SA_PARENT_OFFSET 40
/*
* Intent log header - this on disk structure holds fields to manage
* the log. All fields are 64 bit to easily handle cross architectures.
@ -787,12 +912,14 @@ typedef struct zil_header {
uint64_t zh_pad[5];
} zil_header_t;
#define OBJSET_PHYS_SIZE 2048
typedef struct objset_phys {
dnode_phys_t os_meta_dnode;
zil_header_t os_zil_header;
uint64_t os_type;
uint64_t os_flags;
char os_pad[2048 - sizeof (dnode_phys_t)*3 -
char os_pad[OBJSET_PHYS_SIZE - sizeof (dnode_phys_t)*3 -
sizeof (zil_header_t) - sizeof (uint64_t)*2];
dnode_phys_t os_userused_dnode;
dnode_phys_t os_groupused_dnode;
@ -1174,11 +1301,12 @@ typedef struct vdev {
STAILQ_ENTRY(vdev) v_childlink; /* link in parent's child list */
STAILQ_ENTRY(vdev) v_alllink; /* link in global vdev list */
vdev_list_t v_children; /* children of this vdev */
char *v_name; /* vdev name */
const char *v_name; /* vdev name */
uint64_t v_guid; /* vdev guid */
int v_id; /* index in parent */
int v_ashift; /* offset to block shift */
int v_nparity; /* # parity for raidz */
struct vdev *v_top; /* parent vdev */
int v_nchildren; /* # children */
vdev_state_t v_state; /* current state */
vdev_phys_read_t *v_phys_read; /* read from raw leaf vdev */

File diff suppressed because it is too large Load Diff

54
sys/cddl/boot/zfs/zle.c Normal file
View File

@ -0,0 +1,54 @@
/*
* CDDL HEADER START
*
* 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]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Zero-length encoding. This is a fast and simple algorithm to eliminate
* runs of zeroes. Each chunk of compressed data begins with a length byte, b.
* If b < n (where n is the compression parameter) then the next b + 1 bytes
* are literal values. If b >= n then the next (256 - b + 1) bytes are zero.
*/
static int
zle_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len, int n)
{
unsigned char *src = s_start;
unsigned char *dst = d_start;
unsigned char *s_end = src + s_len;
unsigned char *d_end = dst + d_len;
while (src < s_end && dst < d_end) {
int len = 1 + *src++;
if (len <= n) {
while (len-- != 0)
*dst++ = *src++;
} else {
len -= n;
while (len-- != 0)
*dst++ = 0;
}
}
return (dst == d_end ? 0 : -1);
}

View File

@ -83,8 +83,7 @@ atomic_add_64_nv(volatile uint64_t *target, int64_t delta)
return (newval);
}
#if defined(__sparc64__) || defined(__powerpc__) || defined(__arm__) || \
defined(__mips__)
#if defined(__powerpc__) || defined(__arm__) || defined(__mips__)
void
atomic_or_8(volatile uint8_t *target, uint8_t value)
{
@ -105,23 +104,6 @@ atomic_or_8_nv(volatile uint8_t *target, uint8_t value)
return (newval);
}
#ifndef __LP64__
void *
atomic_cas_ptr(volatile void *target, void *cmp, void *newval)
{
void *oldval, **trg;
mtx_lock(&atomic_mtx);
trg = __DEVOLATILE(void **, target);
oldval = *trg;
if (oldval == cmp)
*trg = newval;
mtx_unlock(&atomic_mtx);
return (oldval);
}
#endif
#ifndef __sparc64__
uint64_t
atomic_cas_64(volatile uint64_t *target, uint64_t cmp, uint64_t newval)
{
@ -134,7 +116,19 @@ atomic_cas_64(volatile uint64_t *target, uint64_t cmp, uint64_t newval)
mtx_unlock(&atomic_mtx);
return (oldval);
}
#endif
uint32_t
atomic_cas_32(volatile uint32_t *target, uint32_t cmp, uint32_t newval)
{
uint32_t oldval;
mtx_lock(&atomic_mtx);
oldval = *target;
if (oldval == cmp)
*target = newval;
mtx_unlock(&atomic_mtx);
return (oldval);
}
void
membar_producer(void)

View File

@ -46,7 +46,7 @@ __FBSDID("$FreeBSD$");
#endif
#ifdef _KERNEL
static MALLOC_DEFINE(M_SOLARIS, "solaris", "Solaris");
MALLOC_DEFINE(M_SOLARIS, "solaris", "Solaris");
#else
#define malloc(size, type, flags) malloc(size)
#define free(addr, type) free(addr)

View File

@ -33,40 +33,22 @@ __FBSDID("$FreeBSD$");
#include <sys/libkern.h>
#include <sys/limits.h>
#include <sys/misc.h>
#include <sys/sunddi.h>
#include <sys/sysctl.h>
char hw_serial[11] = "0";
struct opensolaris_utsname utsname = {
.nodename = "unset",
.sysname = "SunOS"
.machine = MACHINE
};
int
ddi_strtol(const char *str, char **nptr, int base, long *result)
static void
opensolaris_utsname_init(void *arg)
{
*result = strtol(str, nptr, base);
if (*result == 0)
return (EINVAL);
else if (*result == LONG_MIN || *result == LONG_MAX)
return (ERANGE);
return (0);
}
int
ddi_strtoul(const char *str, char **nptr, int base, unsigned long *result)
{
if (str == hw_serial) {
*result = prison0.pr_hostid;
return (0);
}
*result = strtoul(str, nptr, base);
if (*result == 0)
return (EINVAL);
else if (*result == ULONG_MAX)
return (ERANGE);
return (0);
utsname.sysname = ostype;
utsname.nodename = prison0.pr_hostname;
utsname.release = osrelease;
snprintf(utsname.version, sizeof(utsname.version), "%d", osreldate);
}
SYSINIT(opensolaris_utsname_init, SI_SUB_TUNABLES, SI_ORDER_ANY,
opensolaris_utsname_init, NULL);

View File

@ -38,47 +38,47 @@ __FBSDID("$FreeBSD$");
#include <sys/zfs_vfsops.h>
int
secpolicy_nfs(struct ucred *cred)
secpolicy_nfs(cred_t *cr)
{
return (priv_check_cred(cred, PRIV_NFS_DAEMON, 0));
return (priv_check_cred(cr, PRIV_NFS_DAEMON, 0));
}
int
secpolicy_zfs(struct ucred *cred)
secpolicy_zfs(cred_t *cr)
{
return (priv_check_cred(cred, PRIV_VFS_MOUNT, 0));
return (priv_check_cred(cr, PRIV_VFS_MOUNT, 0));
}
int
secpolicy_sys_config(struct ucred *cred, int checkonly __unused)
secpolicy_sys_config(cred_t *cr, int checkonly __unused)
{
return (priv_check_cred(cred, PRIV_ZFS_POOL_CONFIG, 0));
return (priv_check_cred(cr, PRIV_ZFS_POOL_CONFIG, 0));
}
int
secpolicy_zinject(struct ucred *cred)
secpolicy_zinject(cred_t *cr)
{
return (priv_check_cred(cred, PRIV_ZFS_INJECT, 0));
return (priv_check_cred(cr, PRIV_ZFS_INJECT, 0));
}
int
secpolicy_fs_unmount(struct ucred *cred, struct mount *vfsp __unused)
secpolicy_fs_unmount(cred_t *cr, struct mount *vfsp __unused)
{
return (priv_check_cred(cred, PRIV_VFS_UNMOUNT, 0));
return (priv_check_cred(cr, PRIV_VFS_UNMOUNT, 0));
}
int
secpolicy_fs_owner(struct mount *mp, struct ucred *cred)
secpolicy_fs_owner(struct mount *mp, cred_t *cr)
{
if (zfs_super_owner) {
if (cred->cr_uid == mp->mnt_cred->cr_uid &&
cred->cr_prison == mp->mnt_cred->cr_prison) {
if (cr->cr_uid == mp->mnt_cred->cr_uid &&
cr->cr_prison == mp->mnt_cred->cr_prison) {
return (0);
}
}
@ -90,75 +90,129 @@ secpolicy_fs_owner(struct mount *mp, struct ucred *cred)
*/
extern int hardlink_check_uid;
int
secpolicy_basic_link(struct vnode *vp, struct ucred *cred)
secpolicy_basic_link(vnode_t *vp, cred_t *cr)
{
if (!hardlink_check_uid)
return (0);
if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
return (0);
return (priv_check_cred(cred, PRIV_VFS_LINK, 0));
return (priv_check_cred(cr, PRIV_VFS_LINK, 0));
}
int
secpolicy_vnode_stky_modify(struct ucred *cred)
secpolicy_vnode_stky_modify(cred_t *cr)
{
return (EPERM);
}
int
secpolicy_vnode_remove(struct vnode *vp, struct ucred *cred)
secpolicy_vnode_remove(vnode_t *vp, cred_t *cr)
{
if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
return (0);
return (priv_check_cred(cred, PRIV_VFS_ADMIN, 0));
return (priv_check_cred(cr, PRIV_VFS_ADMIN, 0));
}
int
secpolicy_vnode_access(struct ucred *cred, struct vnode *vp, uint64_t owner,
accmode_t accmode)
secpolicy_vnode_access(cred_t *cr, vnode_t *vp, uid_t owner, accmode_t accmode)
{
if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
return (0);
if ((accmode & VREAD) && priv_check_cred(cred, PRIV_VFS_READ, 0) != 0)
if ((accmode & VREAD) && priv_check_cred(cr, PRIV_VFS_READ, 0) != 0)
return (EACCES);
if ((accmode & VWRITE) &&
priv_check_cred(cred, PRIV_VFS_WRITE, 0) != 0) {
priv_check_cred(cr, PRIV_VFS_WRITE, 0) != 0) {
return (EACCES);
}
if (accmode & VEXEC) {
if (vp->v_type == VDIR) {
if (priv_check_cred(cred, PRIV_VFS_LOOKUP, 0) != 0) {
if (priv_check_cred(cr, PRIV_VFS_LOOKUP, 0) != 0)
return (EACCES);
}
} else {
if (priv_check_cred(cred, PRIV_VFS_EXEC, 0) != 0) {
if (priv_check_cred(cr, PRIV_VFS_EXEC, 0) != 0)
return (EACCES);
}
}
}
return (0);
}
/*
* Like secpolicy_vnode_access() but we get the actual wanted mode and the
* current mode of the file, not the missing bits.
*/
int
secpolicy_vnode_setdac(struct vnode *vp, struct ucred *cred, uid_t owner)
secpolicy_vnode_access2(cred_t *cr, vnode_t *vp, uid_t owner,
accmode_t curmode, accmode_t wantmode)
{
accmode_t mode;
if (owner == cred->cr_uid)
mode = ~curmode & wantmode;
if (mode == 0)
return (0);
if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
return (0);
return (priv_check_cred(cred, PRIV_VFS_ADMIN, 0));
return (secpolicy_vnode_access(cr, vp, owner, mode));
}
int
secpolicy_vnode_setattr(struct ucred *cred, struct vnode *vp, struct vattr *vap,
secpolicy_vnode_any_access(cred_t *cr, vnode_t *vp, uid_t owner)
{
static int privs[] = {
PRIV_VFS_ADMIN,
PRIV_VFS_READ,
PRIV_VFS_WRITE,
PRIV_VFS_EXEC,
PRIV_VFS_LOOKUP
};
int i;
if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
return (0);
/* Same as secpolicy_vnode_setdac */
if (owner == cr->cr_uid)
return (0);
for (i = 0; i < sizeof (privs)/sizeof (int); i++) {
boolean_t allzone = B_FALSE;
int priv;
switch (priv = privs[i]) {
case PRIV_VFS_EXEC:
if (vp->v_type == VDIR)
continue;
break;
case PRIV_VFS_LOOKUP:
if (vp->v_type != VDIR)
continue;
break;
}
if (priv_check_cred(cr, priv, 0) == 0)
return (0);
}
return (EPERM);
}
int
secpolicy_vnode_setdac(vnode_t *vp, cred_t *cr, uid_t owner)
{
if (owner == cr->cr_uid)
return (0);
if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
return (0);
return (priv_check_cred(cr, PRIV_VFS_ADMIN, 0));
}
int
secpolicy_vnode_setattr(cred_t *cr, vnode_t *vp, struct vattr *vap,
const struct vattr *ovap, int flags,
int unlocked_access(void *, int, struct ucred *), void *node)
int unlocked_access(void *, int, cred_t *), void *node)
{
int mask = vap->va_mask;
int error;
@ -166,7 +220,7 @@ secpolicy_vnode_setattr(struct ucred *cred, struct vnode *vp, struct vattr *vap,
if (mask & AT_SIZE) {
if (vp->v_type == VDIR)
return (EISDIR);
error = unlocked_access(node, VWRITE, cred);
error = unlocked_access(node, VWRITE, cr);
if (error)
return (error);
}
@ -179,17 +233,17 @@ secpolicy_vnode_setattr(struct ucred *cred, struct vnode *vp, struct vattr *vap,
* In the specific case of creating a set-uid root
* file, we need even more permissions.
*/
error = secpolicy_vnode_setdac(vp, cred, ovap->va_uid);
error = secpolicy_vnode_setdac(vp, cr, ovap->va_uid);
if (error)
return (error);
error = secpolicy_setid_setsticky_clear(vp, vap, ovap, cred);
error = secpolicy_setid_setsticky_clear(vp, vap, ovap, cr);
if (error)
return (error);
} else {
vap->va_mode = ovap->va_mode;
}
if (mask & (AT_UID | AT_GID)) {
error = secpolicy_vnode_setdac(vp, cred, ovap->va_uid);
error = secpolicy_vnode_setdac(vp, cr, ovap->va_uid);
if (error)
return (error);
@ -200,9 +254,9 @@ secpolicy_vnode_setattr(struct ucred *cred, struct vnode *vp, struct vattr *vap,
*/
if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) ||
((mask & AT_GID) && vap->va_gid != ovap->va_gid &&
!groupmember(vap->va_gid, cred))) {
if (secpolicy_fs_owner(vp->v_mount, cred) != 0) {
error = priv_check_cred(cred, PRIV_VFS_CHOWN, 0);
!groupmember(vap->va_gid, cr))) {
if (secpolicy_fs_owner(vp->v_mount, cr) != 0) {
error = priv_check_cred(cr, PRIV_VFS_CHOWN, 0);
if (error)
return (error);
}
@ -210,7 +264,7 @@ secpolicy_vnode_setattr(struct ucred *cred, struct vnode *vp, struct vattr *vap,
if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) ||
((mask & AT_GID) && vap->va_gid != ovap->va_gid)) {
secpolicy_setid_clear(vap, vp, cred);
secpolicy_setid_clear(vap, vp, cr);
}
}
if (mask & (AT_ATIME | AT_MTIME)) {
@ -222,9 +276,9 @@ secpolicy_vnode_setattr(struct ucred *cred, struct vnode *vp, struct vattr *vap,
* If times is non-NULL, ... The caller must be the owner of
* the file or be the super-user.
*/
error = secpolicy_vnode_setdac(vp, cred, ovap->va_uid);
error = secpolicy_vnode_setdac(vp, cr, ovap->va_uid);
if (error && (vap->va_vaflags & VA_UTIMES_NULL))
error = unlocked_access(node, VWRITE, cred);
error = unlocked_access(node, VWRITE, cr);
if (error)
return (error);
}
@ -232,41 +286,42 @@ secpolicy_vnode_setattr(struct ucred *cred, struct vnode *vp, struct vattr *vap,
}
int
secpolicy_vnode_create_gid(struct ucred *cred)
secpolicy_vnode_create_gid(cred_t *cr)
{
return (EPERM);
}
int
secpolicy_vnode_setids_setgids(vnode_t *vp, struct ucred *cred, gid_t gid)
secpolicy_vnode_setids_setgids(vnode_t *vp, cred_t *cr, gid_t gid)
{
if (groupmember(gid, cred))
if (groupmember(gid, cr))
return (0);
if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
return (0);
return (priv_check_cred(cred, PRIV_VFS_SETGID, 0));
return (priv_check_cred(cr, PRIV_VFS_SETGID, 0));
}
int
secpolicy_vnode_setid_retain(struct vnode *vp, struct ucred *cred,
secpolicy_vnode_setid_retain(vnode_t *vp, cred_t *cr,
boolean_t issuidroot __unused)
{
if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
return (0);
return (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0));
return (priv_check_cred(cr, PRIV_VFS_RETAINSUGID, 0));
}
void
secpolicy_setid_clear(struct vattr *vap, struct vnode *vp, struct ucred *cred)
secpolicy_setid_clear(struct vattr *vap, vnode_t *vp, cred_t *cr)
{
if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
return;
if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0) {
if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0)) {
if (priv_check_cred(cr, PRIV_VFS_RETAINSUGID, 0)) {
vap->va_mask |= AT_MODE;
vap->va_mode &= ~(S_ISUID|S_ISGID);
}
@ -274,12 +329,12 @@ secpolicy_setid_clear(struct vattr *vap, struct vnode *vp, struct ucred *cred)
}
int
secpolicy_setid_setsticky_clear(struct vnode *vp, struct vattr *vap,
const struct vattr *ovap, struct ucred *cred)
secpolicy_setid_setsticky_clear(vnode_t *vp, struct vattr *vap,
const struct vattr *ovap, cred_t *cr)
{
int error;
if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
return (0);
/*
@ -288,7 +343,7 @@ secpolicy_setid_setsticky_clear(struct vnode *vp, struct vattr *vap,
* is not a member of. Both of these are allowed in jail(8).
*/
if (vp->v_type != VDIR && (vap->va_mode & S_ISTXT)) {
if (priv_check_cred(cred, PRIV_VFS_STICKYFILE, 0))
if (priv_check_cred(cr, PRIV_VFS_STICKYFILE, 0))
return (EFTYPE);
}
/*
@ -296,15 +351,15 @@ secpolicy_setid_setsticky_clear(struct vnode *vp, struct vattr *vap,
* group-id bit.
*/
if ((vap->va_mode & S_ISGID) != 0) {
error = secpolicy_vnode_setids_setgids(vp, cred, ovap->va_gid);
error = secpolicy_vnode_setids_setgids(vp, cr, ovap->va_gid);
if (error)
return (error);
}
/*
* Deny setting setuid if we are not the file owner.
*/
if ((vap->va_mode & S_ISUID) && ovap->va_uid != cred->cr_uid) {
error = priv_check_cred(cred, PRIV_VFS_ADMIN, 0);
if ((vap->va_mode & S_ISUID) && ovap->va_uid != cr->cr_uid) {
error = priv_check_cred(cr, PRIV_VFS_ADMIN, 0);
if (error)
return (error);
}
@ -319,25 +374,25 @@ secpolicy_fs_mount(cred_t *cr, vnode_t *mvp, struct mount *vfsp)
}
int
secpolicy_vnode_owner(struct vnode *vp, cred_t *cred, uid_t owner)
secpolicy_vnode_owner(vnode_t *vp, cred_t *cr, uid_t owner)
{
if (owner == cred->cr_uid)
if (owner == cr->cr_uid)
return (0);
if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
return (0);
/* XXX: vfs_suser()? */
return (priv_check_cred(cred, PRIV_VFS_MOUNT_OWNER, 0));
return (priv_check_cred(cr, PRIV_VFS_MOUNT_OWNER, 0));
}
int
secpolicy_vnode_chown(struct vnode *vp, cred_t *cred, uid_t owner)
secpolicy_vnode_chown(vnode_t *vp, cred_t *cr, uid_t owner)
{
if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
return (0);
return (priv_check_cred(cred, PRIV_VFS_CHOWN, 0));
return (priv_check_cred(cr, PRIV_VFS_CHOWN, 0));
}
void
@ -357,7 +412,7 @@ secpolicy_fs_mount_clearopts(cred_t *cr, struct mount *vfsp)
* Check privileges for setting xvattr attributes
*/
int
secpolicy_xvattr(struct vnode *vp, xvattr_t *xvap, uid_t owner, cred_t *cr,
secpolicy_xvattr(vnode_t *vp, xvattr_t *xvap, uid_t owner, cred_t *cr,
vtype_t vtype)
{

View File

@ -27,6 +27,8 @@
#include <sys/param.h>
#include <sys/string.h>
#include <sys/kmem.h>
#include <machine/stdarg.h>
#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
@ -71,3 +73,34 @@ strident_canon(char *s, size_t n)
}
*s = 0;
}
/*
* Do not change the length of the returned string; it must be freed
* with strfree().
*/
char *
kmem_asprintf(const char *fmt, ...)
{
int size;
va_list adx;
char *buf;
va_start(adx, fmt);
size = vsnprintf(NULL, 0, fmt, adx) + 1;
va_end(adx);
buf = kmem_alloc(size, KM_SLEEP);
va_start(adx, fmt);
(void) vsnprintf(buf, size, fmt, adx);
va_end(adx);
return (buf);
}
void
strfree(char *str)
{
ASSERT(str != NULL);
kmem_free(str, strlen(str) + 1);
}

View File

@ -0,0 +1,198 @@
/*-
* Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/jail.h>
#include <sys/kernel.h>
#include <sys/libkern.h>
#include <sys/limits.h>
#include <sys/misc.h>
#include <sys/sunddi.h>
#include <sys/sysctl.h>
int
ddi_strtol(const char *str, char **nptr, int base, long *result)
{
*result = strtol(str, nptr, base);
if (*result == 0)
return (EINVAL);
else if (*result == LONG_MIN || *result == LONG_MAX)
return (ERANGE);
return (0);
}
int
ddi_strtoul(const char *str, char **nptr, int base, unsigned long *result)
{
if (str == hw_serial) {
*result = prison0.pr_hostid;
return (0);
}
*result = strtoul(str, nptr, base);
if (*result == 0)
return (EINVAL);
else if (*result == ULONG_MAX)
return (ERANGE);
return (0);
}
int
ddi_strtoull(const char *str, char **nptr, int base, unsigned long long *result)
{
*result = (unsigned long long)strtouq(str, nptr, base);
if (*result == 0)
return (EINVAL);
else if (*result == ULLONG_MAX)
return (ERANGE);
return (0);
}
struct ddi_soft_state_item {
int ssi_item;
void *ssi_data;
LIST_ENTRY(ddi_soft_state_item) ssi_next;
};
struct ddi_soft_state {
size_t ss_size;
kmutex_t ss_lock;
LIST_HEAD(, ddi_soft_state_item) ss_list;
};
static void *
ddi_get_soft_state_locked(struct ddi_soft_state *ss, int item)
{
struct ddi_soft_state_item *itemp;
ASSERT(MUTEX_HELD(&zfsdev_state_lock));
LIST_FOREACH(itemp, &ss->ss_list, ssi_next) {
if (itemp->ssi_item == item)
return (itemp->ssi_data);
}
return (NULL);
}
void *
ddi_get_soft_state(void *state, int item)
{
struct ddi_soft_state *ss = state;
void *data;
mutex_enter(&ss->ss_lock);
data = ddi_get_soft_state_locked(ss, item);
mutex_exit(&ss->ss_lock);
return (data);
}
int
ddi_soft_state_zalloc(void *state, int item)
{
struct ddi_soft_state *ss = state;
struct ddi_soft_state_item *itemp;
itemp = kmem_alloc(sizeof(*itemp), KM_SLEEP);
itemp->ssi_item = item;
itemp->ssi_data = kmem_zalloc(ss->ss_size, KM_SLEEP);
mutex_enter(&ss->ss_lock);
if (ddi_get_soft_state_locked(ss, item) != NULL) {
mutex_exit(&ss->ss_lock);
kmem_free(itemp->ssi_data, ss->ss_size);
kmem_free(itemp, sizeof(*itemp));
return (DDI_FAILURE);
}
LIST_INSERT_HEAD(&ss->ss_list, itemp, ssi_next);
mutex_exit(&ss->ss_lock);
return (DDI_SUCCESS);
}
static void
ddi_soft_state_free_locked(struct ddi_soft_state *ss, int item)
{
struct ddi_soft_state_item *itemp;
ASSERT(MUTEX_HELD(&zfsdev_state_lock));
LIST_FOREACH(itemp, &ss->ss_list, ssi_next) {
if (itemp->ssi_item == item)
break;
}
if (itemp != NULL) {
LIST_REMOVE(itemp, ssi_next);
kmem_free(itemp->ssi_data, ss->ss_size);
kmem_free(itemp, sizeof(*itemp));
}
}
void
ddi_soft_state_free(void *state, int item)
{
struct ddi_soft_state *ss = state;
mutex_enter(&ss->ss_lock);
ddi_soft_state_free_locked(ss, item);
mutex_exit(&ss->ss_lock);
}
int
ddi_soft_state_init(void **statep, size_t size, size_t nitems __unused)
{
struct ddi_soft_state *ss;
ss = kmem_alloc(sizeof(*ss), KM_SLEEP);
mutex_init(&ss->ss_lock, NULL, MUTEX_DEFAULT, NULL);
ss->ss_size = size;
LIST_INIT(&ss->ss_list);
*statep = ss;
return (0);
}
void
ddi_soft_state_fini(void **statep)
{
struct ddi_soft_state *ss = *statep;
struct ddi_soft_state_item *itemp;
int item;
mutex_enter(&ss->ss_lock);
while ((itemp = LIST_FIRST(&ss->ss_list)) != NULL) {
item = itemp->ssi_item;
ddi_soft_state_free_locked(ss, item);
}
mutex_exit(&ss->ss_lock);
mutex_destroy(&ss->ss_lock);
kmem_free(ss, sizeof(*ss));
*statep = NULL;
}

View File

@ -0,0 +1,334 @@
/*-
* Copyright (c) 2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/kmem.h>
#include <sys/sbuf.h>
#include <sys/bus.h>
#include <sys/nvpair.h>
#include <sys/sunddi.h>
#include <sys/sysevent.h>
#include <sys/fm/protocol.h>
struct sysevent {
nvlist_t *se_nvl;
char se_class[128];
char se_subclass[128];
char se_pub[128];
};
sysevent_t *
sysevent_alloc(char *class, char *subclass, char *pub, int flag)
{
struct sysevent *ev;
ASSERT(class != NULL);
ASSERT(subclass != NULL);
ASSERT(pub != NULL);
ASSERT(flag == SE_SLEEP);
ev = kmem_alloc(sizeof(*ev), KM_SLEEP);
ev->se_nvl = NULL;
strlcpy(ev->se_class, class, sizeof(ev->se_class));
strlcpy(ev->se_subclass, subclass, sizeof(ev->se_subclass));
strlcpy(ev->se_pub, pub, sizeof(ev->se_pub));
return ((sysevent_t *)ev);
}
void
sysevent_free(sysevent_t *evp)
{
struct sysevent *ev = (struct sysevent *)evp;
ASSERT(evp != NULL);
if (ev->se_nvl != NULL)
sysevent_free_attr(ev->se_nvl);
kmem_free(ev, sizeof(*ev));
}
int
sysevent_add_attr(sysevent_attr_list_t **ev_attr_list, char *name,
sysevent_value_t *se_value, int flag)
{
nvlist_t *nvl;
int error;
ASSERT(ev_attr_list != NULL);
ASSERT(name != NULL);
ASSERT(se_value != NULL);
ASSERT(flag == SE_SLEEP);
if (strlen(name) >= MAX_ATTR_NAME)
return (SE_EINVAL);
nvl = *ev_attr_list;
if (nvl == NULL) {
if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, KM_SLEEP) != 0)
return (SE_ENOMEM);
}
error = 0;
switch (se_value->value_type) {
case SE_DATA_TYPE_UINT64:
error = nvlist_add_uint64(nvl, name, se_value->value.sv_uint64);
break;
case SE_DATA_TYPE_STRING:
if (strlen(se_value->value.sv_string) >= MAX_STRING_SZ)
error = SE_EINVAL;
if (error == 0) {
error = nvlist_add_string(nvl, name,
se_value->value.sv_string);
}
break;
default:
printf("%s: type %d is not implemented\n", __func__,
se_value->value_type);
break;
}
if (error != 0) {
nvlist_free(nvl);
return (error);
}
*ev_attr_list = nvl;
return (0);
}
void
sysevent_free_attr(sysevent_attr_list_t *ev_attr_list)
{
nvlist_free(ev_attr_list);
}
int
sysevent_attach_attributes(sysevent_t *evp, sysevent_attr_list_t *ev_attr_list)
{
struct sysevent *ev = (struct sysevent *)evp;
ASSERT(ev->se_nvl == NULL);
ev->se_nvl = ev_attr_list;
return (0);
}
void
sysevent_detach_attributes(sysevent_t *evp)
{
struct sysevent *ev = (struct sysevent *)evp;
ASSERT(ev->se_nvl != NULL);
ev->se_nvl = NULL;
}
int
log_sysevent(sysevent_t *evp, int flag, sysevent_id_t *eid)
{
struct sysevent *ev = (struct sysevent *)evp;
struct sbuf *sb;
const char *type;
char typestr[128];
nvpair_t *elem = NULL;
ASSERT(evp != NULL);
ASSERT(ev->se_nvl != NULL);
ASSERT(flag == SE_SLEEP);
ASSERT(eid != NULL);
sb = sbuf_new_auto();
if (sb == NULL)
return (SE_ENOMEM);
type = NULL;
while ((elem = nvlist_next_nvpair(ev->se_nvl, elem)) != NULL) {
switch (nvpair_type(elem)) {
case DATA_TYPE_BOOLEAN:
{
boolean_t value;
(void) nvpair_value_boolean_value(elem, &value);
sbuf_printf(sb, " %s=%s", nvpair_name(elem),
value ? "true" : "false");
break;
}
case DATA_TYPE_UINT8:
{
uint8_t value;
(void) nvpair_value_uint8(elem, &value);
sbuf_printf(sb, " %s=%hhu", nvpair_name(elem), value);
break;
}
case DATA_TYPE_INT32:
{
int32_t value;
(void) nvpair_value_int32(elem, &value);
sbuf_printf(sb, " %s=%jd", nvpair_name(elem),
(intmax_t)value);
break;
}
case DATA_TYPE_UINT32:
{
uint32_t value;
(void) nvpair_value_uint32(elem, &value);
sbuf_printf(sb, " %s=%ju", nvpair_name(elem),
(uintmax_t)value);
break;
}
case DATA_TYPE_INT64:
{
int64_t value;
(void) nvpair_value_int64(elem, &value);
sbuf_printf(sb, " %s=%jd", nvpair_name(elem),
(intmax_t)value);
break;
}
case DATA_TYPE_UINT64:
{
uint64_t value;
(void) nvpair_value_uint64(elem, &value);
sbuf_printf(sb, " %s=%ju", nvpair_name(elem),
(uintmax_t)value);
break;
}
case DATA_TYPE_STRING:
{
char *value;
(void) nvpair_value_string(elem, &value);
sbuf_printf(sb, " %s=%s", nvpair_name(elem), value);
if (strcmp(FM_CLASS, nvpair_name(elem)) == 0)
type = value;
break;
}
case DATA_TYPE_UINT8_ARRAY:
{
uint8_t *value;
uint_t ii, nelem;
(void) nvpair_value_uint8_array(elem, &value, &nelem);
sbuf_printf(sb, " %s=", nvpair_name(elem));
for (ii = 0; ii < nelem; ii++)
sbuf_printf(sb, "%02hhx", value[ii]);
break;
}
case DATA_TYPE_UINT16_ARRAY:
{
uint16_t *value;
uint_t ii, nelem;
(void) nvpair_value_uint16_array(elem, &value, &nelem);
sbuf_printf(sb, " %s=", nvpair_name(elem));
for (ii = 0; ii < nelem; ii++)
sbuf_printf(sb, "%04hx", value[ii]);
break;
}
case DATA_TYPE_UINT32_ARRAY:
{
uint32_t *value;
uint_t ii, nelem;
(void) nvpair_value_uint32_array(elem, &value, &nelem);
sbuf_printf(sb, " %s=", nvpair_name(elem));
for (ii = 0; ii < nelem; ii++)
sbuf_printf(sb, "%08jx", (uintmax_t)value[ii]);
break;
}
case DATA_TYPE_UINT64_ARRAY:
{
uint64_t *value;
uint_t ii, nelem;
(void) nvpair_value_uint64_array(elem, &value, &nelem);
sbuf_printf(sb, " %s=", nvpair_name(elem));
for (ii = 0; ii < nelem; ii++)
sbuf_printf(sb, "%016jx", (uintmax_t)value[ii]);
break;
}
default:
printf("%s: type %d is not implemented\n", __func__,
nvpair_type(elem));
break;
}
}
if (sbuf_finish(sb) != 0) {
sbuf_delete(sb);
return (SE_ENOMEM);
}
if (type == NULL)
type = ev->se_subclass;
if (strncmp(type, "ESC_ZFS_", 8) == 0) {
snprintf(typestr, sizeof(typestr), "misc.fs.zfs.%s", type + 8);
type = typestr;
}
devctl_notify("ZFS", "ZFS", type, sbuf_data(sb));
sbuf_delete(sb);
return (0);
}
int
_ddi_log_sysevent(char *vendor, char *class, char *subclass,
nvlist_t *attr_list, sysevent_id_t *eidp, int flag)
{
sysevent_t *ev;
int ret;
ASSERT(vendor != NULL);
ASSERT(class != NULL);
ASSERT(subclass != NULL);
ASSERT(attr_list != NULL);
ASSERT(eidp != NULL);
ASSERT(flag == DDI_SLEEP);
ev = sysevent_alloc(class, subclass, vendor, SE_SLEEP);
ASSERT(ev != NULL);
(void)sysevent_attach_attributes(ev, attr_list);
ret = log_sysevent(ev, SE_SLEEP, eidp);
sysevent_detach_attributes(ev);
sysevent_free(ev);
return (ret);
}

View File

@ -115,12 +115,17 @@ taskqid_t
taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t flags)
{
struct ostask *task;
int mflag;
int mflag, prio;
if ((flags & (TQ_SLEEP | TQ_NOQUEUE)) == TQ_SLEEP)
mflag = M_WAITOK;
else
mflag = M_NOWAIT;
/*
* If TQ_FRONT is given, we want higher priority for this task, so it
* can go at the front of the queue.
*/
prio = !!(flags & TQ_FRONT);
task = uma_zalloc(taskq_zone, mflag);
if (task == NULL)
@ -129,7 +134,7 @@ taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t flags)
task->ost_func = func;
task->ost_arg = arg;
TASK_INIT(&task->ost_task, 0, taskq_run, task);
TASK_INIT(&task->ost_task, prio, taskq_run, task);
taskqueue_enqueue(tq->tq_queue, &task->ost_task);
return ((taskqid_t)(void *)task);
@ -148,17 +153,24 @@ taskq_run_safe(void *arg, int pending __unused)
}
taskqid_t
taskq_dispatch_safe(taskq_t *tq, task_func_t func, void *arg,
taskq_dispatch_safe(taskq_t *tq, task_func_t func, void *arg, u_int flags,
struct ostask *task)
{
int prio;
ASSERT(task->ost_magic != TASKQ_MAGIC);
/*
* If TQ_FRONT is given, we want higher priority for this task, so it
* can go at the front of the queue.
*/
prio = !!(flags & TQ_FRONT);
task->ost_magic = TASKQ_MAGIC;
task->ost_func = func;
task->ost_arg = arg;
TASK_INIT(&task->ost_task, 0, taskq_run_safe, task);
TASK_INIT(&task->ost_task, prio, taskq_run_safe, task);
taskqueue_enqueue(tq->tq_queue, &task->ost_task);
return ((taskqid_t)(void *)task);

View File

@ -115,10 +115,10 @@ int
mount_snapshot(kthread_t *td, vnode_t **vpp, const char *fstype, char *fspath,
char *fspec, int fsflags)
{
struct mount *mp;
struct vfsconf *vfsp;
struct mount *mp;
vnode_t *vp, *mvp;
struct ucred *cr;
vnode_t *vp;
int error;
/*
@ -153,8 +153,10 @@ mount_snapshot(kthread_t *td, vnode_t **vpp, const char *fstype, char *fspath,
/*
* Allocate and initialize the filesystem.
* We don't want regular user that triggered snapshot mount to be able
* to unmount it, so pass credentials of the parent mount.
*/
mp = vfs_mount_alloc(vp, vfsp, fspath, td->td_ucred);
mp = vfs_mount_alloc(vp, vfsp, fspath, vp->v_mount->mnt_cred);
mp->mnt_optnew = NULL;
vfs_setmntopt(mp, "from", fspec, 0);
@ -164,8 +166,7 @@ mount_snapshot(kthread_t *td, vnode_t **vpp, const char *fstype, char *fspath,
/*
* Set the mount level flags.
*/
mp->mnt_flag &= ~MNT_UPDATEMASK;
mp->mnt_flag |= fsflags & (MNT_UPDATEMASK | MNT_FORCE | MNT_ROOTFS);
mp->mnt_flag = fsflags & MNT_UPDATEMASK;
/*
* Snapshots are always read-only.
*/
@ -175,13 +176,6 @@ mount_snapshot(kthread_t *td, vnode_t **vpp, const char *fstype, char *fspath,
* mount(8) and df(1) output.
*/
mp->mnt_flag |= MNT_IGNORE;
/*
* Unprivileged user can trigger mounting a snapshot, but we don't want
* him to unmount it, so we switch to privileged of original mount.
*/
crfree(mp->mnt_cred);
mp->mnt_cred = crdup(vp->v_mount->mnt_cred);
mp->mnt_stat.f_owner = mp->mnt_cred->cr_uid;
/*
* XXX: This is evil, but we can't mount a snapshot as a regular user.
* XXX: Is is safe when snapshot is mounted from within a jail?
@ -191,17 +185,25 @@ mount_snapshot(kthread_t *td, vnode_t **vpp, const char *fstype, char *fspath,
error = VFS_MOUNT(mp);
td->td_ucred = cr;
if (error == 0) {
if (mp->mnt_opt != NULL)
vfs_freeopts(mp->mnt_opt);
mp->mnt_opt = mp->mnt_optnew;
(void)VFS_STATFS(mp, &mp->mnt_stat);
if (error != 0) {
vrele(vp);
vfs_unbusy(mp);
vfs_mount_destroy(mp);
*vpp = NULL;
return (error);
}
if (mp->mnt_opt != NULL)
vfs_freeopts(mp->mnt_opt);
mp->mnt_opt = mp->mnt_optnew;
(void)VFS_STATFS(mp, &mp->mnt_stat);
/*
* Prevent external consumers of mount options from reading
* mnt_optnew.
*/
mp->mnt_optnew = NULL;
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
#ifdef FREEBSD_NAMECACHE
cache_purge(vp);
@ -209,27 +211,17 @@ mount_snapshot(kthread_t *td, vnode_t **vpp, const char *fstype, char *fspath,
VI_LOCK(vp);
vp->v_iflag &= ~VI_MOUNT;
VI_UNLOCK(vp);
if (error == 0) {
vnode_t *mvp;
vp->v_mountedhere = mp;
/*
* Put the new filesystem on the mount list.
*/
mtx_lock(&mountlist_mtx);
TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
mtx_unlock(&mountlist_mtx);
vfs_event_signal(NULL, VQ_MOUNT, 0);
if (VFS_ROOT(mp, LK_EXCLUSIVE, &mvp))
panic("mount: lost mount");
vput(vp);
vfs_unbusy(mp);
*vpp = mvp;
} else {
vput(vp);
vfs_unbusy(mp);
vfs_mount_destroy(mp);
*vpp = NULL;
}
return (error);
vp->v_mountedhere = mp;
/* Put the new filesystem on the mount list. */
mtx_lock(&mountlist_mtx);
TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
mtx_unlock(&mountlist_mtx);
vfs_event_signal(NULL, VQ_MOUNT, 0);
if (VFS_ROOT(mp, LK_EXCLUSIVE, &mvp))
panic("mount: lost mount");
vput(vp);
vfs_unbusy(mp);
*vpp = mvp;
return (0);
}

View File

@ -229,6 +229,15 @@ zone_destroy(void *arg)
free(head, M_ZONES);
}
uint32_t
zone_get_hostid(void *ptr)
{
KASSERT(ptr == NULL, ("only NULL pointer supported in %s", __func__));
return ((uint32_t)curthread->td_ucred->cr_prison->pr_hostid);
}
static void
zone_sysinit(void *arg __unused)
{

View File

@ -41,9 +41,10 @@ extern void atomic_add_64(volatile uint64_t *target, int64_t delta);
extern void atomic_dec_64(volatile uint64_t *target);
#endif
#ifndef __LP64__
extern void *atomic_cas_ptr(volatile void *target, void *cmp, void *newval);
#endif
#ifndef __sparc64__
extern uint32_t atomic_cas_32(volatile uint32_t *target, uint32_t cmp,
uint32_t newval);
extern uint64_t atomic_cas_64(volatile uint64_t *target, uint64_t cmp,
uint64_t newval);
#endif
@ -118,13 +119,20 @@ atomic_inc_64_nv(volatile uint64_t *target)
return (atomic_add_64_nv(target, 1));
}
#ifdef __LP64__
#if !defined(COMPAT_32BIT) && defined(__LP64__)
static __inline void *
atomic_cas_ptr(volatile void *target, void *cmp, void *newval)
{
return ((void *)atomic_cas_64((volatile uint64_t *)target, (uint64_t)cmp,
(uint64_t)newval));
return ((void *)atomic_cas_64((volatile uint64_t *)target,
(uint64_t)cmp, (uint64_t)newval));
}
#endif
#else
static __inline void *
atomic_cas_ptr(volatile void *target, void *cmp, void *newval)
{
return ((void *)atomic_cas_32((volatile uint32_t *)target,
(uint32_t)cmp, (uint32_t)newval));
}
#endif /* !defined(COMPAT_32BIT) && defined(__LP64__) */
#endif /* !_OPENSOLARIS_SYS_ATOMIC_H_ */

View File

@ -59,9 +59,31 @@
* Macros to convert from a specific byte order to/from native byte order
*/
#if _BYTE_ORDER == _BIG_ENDIAN
#define BE_8(x) BMASK_8(x)
#define BE_16(x) BMASK_16(x)
#define BE_32(x) BMASK_32(x)
#define BE_64(x) BMASK_64(x)
#define LE_8(x) BSWAP_8(x)
#define LE_16(x) BSWAP_16(x)
#define LE_32(x) BSWAP_32(x)
#define LE_64(x) BSWAP_64(x)
#else
#define LE_8(x) BMASK_8(x)
#define LE_16(x) BMASK_16(x)
#define LE_32(x) BMASK_32(x)
#define LE_64(x) BMASK_64(x)
#define BE_8(x) BSWAP_8(x)
#define BE_16(x) BSWAP_16(x)
#define BE_32(x) BSWAP_32(x)
#define BE_64(x) BSWAP_64(x)
#endif
#if _BYTE_ORDER == _BIG_ENDIAN
#define htonll(x) BMASK_64(x)
#define ntohll(x) BMASK_64(x)
#else
#define htonll(x) BSWAP_64(x)
#define ntohll(x) BSWAP_64(x)
#endif
#endif /* _OPENSOLARIS_SYS_BYTEORDER_H_ */

View File

@ -29,11 +29,14 @@
#ifndef _OPENSOLARIS_SYS_DIRENT_H_
#define _OPENSOLARIS_SYS_DIRENT_H_
#include <sys/types.h>
#include_next <sys/dirent.h>
typedef struct dirent dirent64_t;
typedef ino_t ino64_t;
#define dirent64 dirent
#define ino64_t ino_t
#define d_ino d_fileno

View File

@ -31,26 +31,30 @@
#include_next <sys/file.h>
#define FKIOCTL 0x80000000 /* ioctl addresses are from kernel */
#ifdef _KERNEL
typedef struct file file_t;
static __inline file_t *
getf(int fd, int write)
getf(int fd)
{
struct file *fp;
if (write && fget_write(curthread, fd, &fp) == 0)
return (fp);
else if (!write && fget_read(curthread, fd, &fp) == 0)
if (fget(curthread, fd, &fp) == 0)
return (fp);
return (NULL);
}
static __inline void
releasef(file_t *fp)
releasef(int fd)
{
struct file *fp;
fdrop(fp, curthread);
if (fget(curthread, fd, &fp) == 0) {
fdrop(fp, curthread);
fdrop(fp, curthread);
}
}
#endif /* _KERNEL */

View File

@ -37,10 +37,16 @@
#include <vm/vm.h>
#include <vm/vm_extern.h>
MALLOC_DECLARE(M_SOLARIS);
#define POINTER_IS_VALID(p) (!((uintptr_t)(p) & 0x3))
#define POINTER_INVALIDATE(pp) (*(pp) = (void *)((uintptr_t)(*(pp)) | 0x1))
#define KM_SLEEP M_WAITOK
#define KM_PUSHPAGE M_WAITOK
#define KM_NOSLEEP M_NOWAIT
#define KMC_NODEBUG 0
#define KMC_NOTOUCH 0
typedef struct kmem_cache {
char kc_name[32];
@ -75,4 +81,6 @@ void *calloc(size_t n, size_t s);
#define kmem_zalloc(size, kmflags) zfs_kmem_alloc((size), (kmflags) | M_ZERO)
#define kmem_free(buf, size) zfs_kmem_free((buf), (size))
#define kmem_cache_set_move(cache, movefunc) do { } while (0)
#endif /* _OPENSOLARIS_SYS_KMEM_H_ */

View File

@ -29,7 +29,9 @@
#ifndef _OPENSOLARIS_SYS_MISC_H_
#define _OPENSOLARIS_SYS_MISC_H_
#define MAXUID 2147483647
#include <sys/limits.h>
#define MAXUID UID_MAX
#define SPEC_MAXOFFSET_T OFF_MAX
@ -45,8 +47,11 @@
#ifdef _KERNEL
struct opensolaris_utsname {
char *nodename;
char *sysname;
char *sysname;
char *nodename;
char *release;
char version[32];
char *machine;
};
extern char hw_serial[11];

View File

@ -29,6 +29,8 @@
#ifndef _OPENSOLARIS_SYS_MOUNT_H_
#define _OPENSOLARIS_SYS_MOUNT_H_
#include <sys/param.h>
#include_next <sys/mount.h>
#define MS_FORCE MNT_FORCE

View File

@ -54,7 +54,7 @@ typedef struct sx kmutex_t;
#define mutex_init(lock, desc, type, arg) do { \
const char *_name; \
ASSERT((type) == MUTEX_DEFAULT); \
ASSERT((type) == 0 || (type) == MUTEX_DEFAULT); \
KASSERT(((lock)->lock_object.lo_flags & LO_ALLMASK) != \
LO_EXPECTED, ("lock %s already initialized", #lock)); \
bzero((lock), sizeof(struct sx)); \

View File

@ -36,41 +36,39 @@
#include <sys/vnode.h>
struct mount;
struct ucred;
struct vattr;
struct vnode;
int secpolicy_nfs(struct ucred *cred);
int secpolicy_zfs(struct ucred *cred);
int secpolicy_sys_config(struct ucred *cred, int checkonly);
int secpolicy_zinject(struct ucred *cred);
int secpolicy_fs_unmount(struct ucred *cred, struct mount *vfsp);
int secpolicy_basic_link(struct vnode *vp, struct ucred *cred);
int secpolicy_vnode_owner(struct vnode *vp, cred_t *cred, uid_t owner);
int secpolicy_vnode_chown(struct vnode *vp, cred_t *cred, uid_t owner);
int secpolicy_vnode_stky_modify(struct ucred *cred);
int secpolicy_vnode_remove(struct vnode *vp, struct ucred *cred);
int secpolicy_vnode_access(struct ucred *cred, struct vnode *vp,
uint64_t owner, accmode_t accmode);
int secpolicy_vnode_setdac(struct vnode *vp, struct ucred *cred,
uid_t owner);
int secpolicy_vnode_setattr(struct ucred *cred, struct vnode *vp,
struct vattr *vap, const struct vattr *ovap, int flags,
int unlocked_access(void *, int, struct ucred *), void *node);
int secpolicy_vnode_create_gid(struct ucred *cred);
int secpolicy_vnode_setids_setgids(struct vnode *vp, struct ucred *cred,
gid_t gid);
int secpolicy_vnode_setid_retain(struct vnode *vp, struct ucred *cred,
int secpolicy_nfs(cred_t *cr);
int secpolicy_zfs(cred_t *crd);
int secpolicy_sys_config(cred_t *cr, int checkonly);
int secpolicy_zinject(cred_t *cr);
int secpolicy_fs_unmount(cred_t *cr, struct mount *vfsp);
int secpolicy_basic_link(vnode_t *vp, cred_t *cr);
int secpolicy_vnode_owner(vnode_t *vp, cred_t *cr, uid_t owner);
int secpolicy_vnode_chown(vnode_t *vp, cred_t *cr, uid_t owner);
int secpolicy_vnode_stky_modify(cred_t *cr);
int secpolicy_vnode_remove(vnode_t *vp, cred_t *cr);
int secpolicy_vnode_access(cred_t *cr, vnode_t *vp, uid_t owner,
accmode_t accmode);
int secpolicy_vnode_access2(cred_t *cr, vnode_t *vp, uid_t owner,
accmode_t curmode, accmode_t wantmode);
int secpolicy_vnode_any_access(cred_t *cr, vnode_t *vp, uid_t owner);
int secpolicy_vnode_setdac(vnode_t *vp, cred_t *cr, uid_t owner);
int secpolicy_vnode_setattr(cred_t *cr, vnode_t *vp, struct vattr *vap,
const struct vattr *ovap, int flags,
int unlocked_access(void *, int, cred_t *), void *node);
int secpolicy_vnode_create_gid(cred_t *cr);
int secpolicy_vnode_setids_setgids(vnode_t *vp, cred_t *cr, gid_t gid);
int secpolicy_vnode_setid_retain(vnode_t *vp, cred_t *cr,
boolean_t issuidroot);
void secpolicy_setid_clear(struct vattr *vap, struct vnode *vp,
struct ucred *cred);
int secpolicy_setid_setsticky_clear(struct vnode *vp, struct vattr *vap,
const struct vattr *ovap, struct ucred *cred);
int secpolicy_fs_owner(struct mount *vfsp, struct ucred *cred);
void secpolicy_setid_clear(struct vattr *vap, vnode_t *vp, cred_t *cr);
int secpolicy_setid_setsticky_clear(vnode_t *vp, struct vattr *vap,
const struct vattr *ovap, cred_t *cr);
int secpolicy_fs_owner(struct mount *vfsp, cred_t *cr);
int secpolicy_fs_mount(cred_t *cr, vnode_t *mvp, struct mount *vfsp);
void secpolicy_fs_mount_clearopts(cred_t *cr, struct mount *vfsp);
int secpolicy_xvattr(struct vnode *vp, xvattr_t *xvap, uid_t owner,
cred_t *cr, vtype_t vtype);
int secpolicy_xvattr(vnode_t *vp, xvattr_t *xvap, uid_t owner, cred_t *cr,
vtype_t vtype);
int secpolicy_smb(cred_t *cr);
#endif /* _KERNEL */

Some files were not shown because too many files have changed in this diff Show More