From owner-freebsd-fs@FreeBSD.ORG Sun Jun 10 07:00:43 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 67AAD106564A for ; Sun, 10 Jun 2012 07:00:43 +0000 (UTC) (envelope-from patpro@patpro.net) Received: from rack.patpro.net (rack.patpro.net [193.30.227.216]) by mx1.freebsd.org (Postfix) with ESMTP id F1FA78FC16 for ; Sun, 10 Jun 2012 07:00:42 +0000 (UTC) Received: from rack.patpro.net (localhost [127.0.0.1]) by rack.patpro.net (Postfix) with ESMTP id 4C52C1CC020 for ; Sun, 10 Jun 2012 08:53:11 +0200 (CEST) X-Virus-Scanned: amavisd-new at patpro.net Received: from amavis-at-patpro.net ([127.0.0.1]) by rack.patpro.net (rack.patpro.net [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id YK_ncZEK3hmP for ; Sun, 10 Jun 2012 08:53:09 +0200 (CEST) Received: from [127.0.0.1] (localhost [127.0.0.1]) by rack.patpro.net (Postfix) with ESMTP for ; Sun, 10 Jun 2012 08:53:09 +0200 (CEST) From: Patrick Proniewski Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable Date: Sun, 10 Jun 2012 08:53:08 +0200 Message-Id: <9A54A14B-7DA4-48AD-8198-63A8572D3DB3@patpro.net> To: freebsd-fs@freebsd.org Mime-Version: 1.0 (Apple Message framework v1084) X-Mailer: Apple Mail (2.1084) Subject: [zfs] need help with a bug (PR 156781) X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 10 Jun 2012 07:00:43 -0000 Hello, I'm running various FreeBSD 8 amd64 servers, and some of them use ZFS = extensively. Unfortunately, I'm hit by the bug "PR 156781" = (). After an undetermined uptime, the affected server will lose the ability = to list some of its .zfs/.snappshot: ls -l .zfs ls: snapshot: Bad file descriptor It doesn't look critical at this point, because snapshots still work = (creation/deletion), but you won't be able to access them via cd = .zfs/snapshot/... In fact, it is critical. If you try to unmount the affected ZFS volume, = your shell will freeze, and you have to reconnect in a new one. And more = importantly, the whole OS will freeze when you issue a reboot, meaning = it will never reboot until someone pushes the power button of the box. It's a very nasty bug when your box is 400 km away in a data center, and = you need to ask your hosting provider to push that button. I would be happy if the PR 156781 could be modified so that it says its = Severity is critical, and it affects both FreeBSD 8.1-RELEASE-p5 amd64, = FreeBSD 8.2-RELEASE-p3 amd64, and FreeBSD 8.2-STABLE sparc64 (ie. not = just FreeBSD 8.2-STABLE sparc64). And I would be very very happy, if someone could fix this bug, it's = unfortunately way out of my reach :/ FreeBSD si 8.2-RELEASE-p3 FreeBSD 8.2-RELEASE-p3 #0: Tue Sep 27 = 18:45:57 UTC 2011 =20 root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC = amd64 $ grep ZFS /var/run/dmesg.boot ZFS filesystem version 4 ZFS storage pool version 15 $ zpool upgrade -a This system is currently running ZFS pool version 15. All pools are formatted using this version. $ zfs upgrade -a 0 filesystems upgraded 265 filesystems already at this version and=20 FreeBSD rack.patpro.net 8.1-RELEASE-p5 FreeBSD 8.1-RELEASE-p5 = #0: Tue Sep 27 16:49:00 UTC 2011 =20 root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC = amd64 $ grep ZFS /var/run/dmesg.boot=20 ZFS filesystem version 3 ZFS storage pool version 14 $ zpool upgrade -a This system is currently running ZFS pool version 14. All pools are formatted using this version. $ zfs upgrade -ra 0 filesystems upgraded 19 filesystems already at this version regards, patpro (I'm subscribed to the digest, fell free to Cc. me)= From owner-freebsd-fs@FreeBSD.ORG Sun Jun 10 23:36:16 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id D11F8106566C for ; Sun, 10 Jun 2012 23:36:16 +0000 (UTC) (envelope-from feld@feld.me) Received: from feld.me (unknown [IPv6:2607:f4e0:100:300::2]) by mx1.freebsd.org (Postfix) with ESMTP id A73F88FC0C for ; Sun, 10 Jun 2012 23:36:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=feld.me; s=blargle; h=Message-Id:References:In-Reply-To:Subject:To:From:Date:Content-Type:Mime-Version; bh=zexCxTXRRxgs7eGYMbP+3tikNPdP/6K4dB+I33HuGG0=; b=GpKaAWyOwSt1WoyTl05s52/uFpgZpRHfSI6Z2XKdPmcVANOJIjf6SKOAVzjtJe/oAEsFBJMFJhd0NQQTgTpFiV45supS9MvhTlVPrI6KF7gFhkDuqJJLfxVxj94AUG34; Received: from localhost ([127.0.0.1] helo=mwi1.coffeenet.org) by feld.me with esmtp (Exim 4.77 (FreeBSD)) (envelope-from ) id 1Sdrg6-000G00-Cg for freebsd-fs@freebsd.org; Sun, 10 Jun 2012 18:36:15 -0500 Received: from feld@feld.me by mwi1.coffeenet.org (Archiveopteryx 3.1.4) with esmtpsa id 1339371368-26372-26371/5/63; Sun, 10 Jun 2012 23:36:08 +0000 Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8; format=flowed Date: Sun, 10 Jun 2012 18:36:08 -0500 From: Mark Felder To: freebsd-fs@freebsd.org In-Reply-To: <9A54A14B-7DA4-48AD-8198-63A8572D3DB3@patpro.net> References: <9A54A14B-7DA4-48AD-8198-63A8572D3DB3@patpro.net> Message-Id: X-Sender: feld@feld.me User-Agent: Roundcube Webmail/0.6 X-SA-Score: -1.5 Subject: Re: [zfs] need help with a bug (PR 156781) X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 10 Jun 2012 23:36:16 -0000 FreeBSD 8.1 and 8.2 are actually quite old these days. I don't think this bug is reproducible on 8.3 or 9.0. Can you upgrade and report back? Thanks From owner-freebsd-fs@FreeBSD.ORG Mon Jun 11 04:30:02 2012 Return-Path: Delivered-To: freebsd-fs@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id CF732106566B for ; Mon, 11 Jun 2012 04:30:02 +0000 (UTC) (envelope-from matthew@FreeBSD.org) Received: from smtp.infracaninophile.co.uk (smtp6.infracaninophile.co.uk [IPv6:2001:8b0:151:1:3cd3:cd67:fafa:3d78]) by mx1.freebsd.org (Postfix) with ESMTP id 35BA38FC1B for ; Mon, 11 Jun 2012 04:30:02 +0000 (UTC) Received: from seedling.black-earth.co.uk (seedling.black-earth.co.uk [81.187.76.163]) (authenticated bits=0) by smtp.infracaninophile.co.uk (8.14.5/8.14.5) with ESMTP id q5B4TvWZ031259 (version=TLSv1/SSLv3 cipher=DHE-RSA-CAMELLIA256-SHA bits=256 verify=NO) for ; Mon, 11 Jun 2012 05:29:57 +0100 (BST) (envelope-from matthew@FreeBSD.org) X-DKIM: OpenDKIM Filter v2.5.2 smtp.infracaninophile.co.uk q5B4TvWZ031259 Authentication-Results: smtp.infracaninophile.co.uk/q5B4TvWZ031259; dkim=none (no signature); dkim-adsp=none Message-ID: <4FD5743D.4030002@FreeBSD.org> Date: Mon, 11 Jun 2012 05:29:49 +0100 From: Matthew Seaman User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:13.0) Gecko/20120601 Thunderbird/13.0 MIME-Version: 1.0 To: freebsd-fs@FreeBSD.org References: <9A54A14B-7DA4-48AD-8198-63A8572D3DB3@patpro.net> In-Reply-To: X-Enigmail-Version: 1.4.2 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="------------enigC0709C448B5D193A4FE27A60" X-Virus-Scanned: clamav-milter 0.97.4 at lucid-nonsense.infracaninophile.co.uk X-Virus-Status: Clean X-Spam-Status: No, score=-2.7 required=5.0 tests=ALL_TRUSTED,AWL,BAYES_00 autolearn=ham version=3.3.2 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on lucid-nonsense.infracaninophile.co.uk Cc: Subject: Re: [zfs] need help with a bug (PR 156781) X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Jun 2012 04:30:02 -0000 This is an OpenPGP/MIME signed message (RFC 2440 and 3156) --------------enigC0709C448B5D193A4FE27A60 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable On 11/06/2012 00:36, Mark Felder wrote: > FreeBSD 8.1 and 8.2 are actually quite old these days. I don't think > this bug is reproducible on 8.3 or 9.0. Can you upgrade and report back= ? I'm seeing exactly this on stable/9. Seems to be triggered by doing certain IO patterns -- so csup of the ports cvs repo and subsequent checkout will cause the effect, but direct csup of the ports tree doesn't= =2E This is using a zpool created under 8.0-RELEASE and subsequently updated. I wanted to try splitting the mirror using zfs {send,receive} to copy the filesystem into a brand-new zpool to see if that made any difference, but this is my main server and I haven't had the chance to do that yet. Cheers, Matthew --=20 Dr Matthew J Seaman MA, D.Phil. PGP: http://www.infracaninophile.co.uk/pgpkey --------------enigC0709C448B5D193A4FE27A60 Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG/MacGPG2 v2.0.16 (Darwin) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAk/VdEUACgkQ8Mjk52CukIzgCwCgjsyVYddKq3o9Ilh4ACrG02Fw wHcAnRMmhqdlgj55jIxcUWQ+Bv5K1WFL =BTOc -----END PGP SIGNATURE----- --------------enigC0709C448B5D193A4FE27A60-- From owner-freebsd-fs@FreeBSD.ORG Mon Jun 11 08:30:11 2012 Return-Path: Delivered-To: freebsd-fs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 0625B1065670 for ; Mon, 11 Jun 2012 08:30:10 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id D7A5F8FC12 for ; Mon, 11 Jun 2012 08:30:10 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.5/8.14.5) with ESMTP id q5B8UA2F078650 for ; Mon, 11 Jun 2012 08:30:10 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.5/8.14.5/Submit) id q5B8UAdn078645; Mon, 11 Jun 2012 08:30:10 GMT (envelope-from gnats) Date: Mon, 11 Jun 2012 08:30:10 GMT Message-Id: <201206110830.q5B8UAdn078645@freefall.freebsd.org> To: freebsd-fs@FreeBSD.org From: Peter Maloney Cc: Subject: Re: kern/161968: [zfs] [hang] renaming snapshot with -r including a zvol snapshot causes total ZFS freeze/lockup X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Peter Maloney List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Jun 2012 08:30:11 -0000 The following reply was made to PR kern/161968; it has been noted by GNATS. From: Peter Maloney To: bug-followup@FreeBSD.org, peter.maloney@brockmann-consult.de Cc: Subject: Re: kern/161968: [zfs] [hang] renaming snapshot with -r including a zvol snapshot causes total ZFS freeze/lockup Date: Mon, 11 Jun 2012 10:23:58 +0200 This is a multi-part message in MIME format. --------------060109020708020504050507 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit I've tested this in 8.3-RELEASE, and 8.3-STABLE pulled last week. *Both hang*, even though 8.2-STABLE in Feb 2012 did not hang. First terminal: Snapshot Renaming from to 1 load: 0.00 cmd: zfs 57149 [tx->tx_sync_done_cv)] 104.03r 0.00u 0.00s 0% 1920k Second: # zfs list load: 0.00 cmd: zfs 58403 [spa_namespace_lock] 119.06r 0.00u 0.00s 0% 1796k --------------060109020708020504050507 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit I've tested this in 8.3-RELEASE, and 8.3-STABLE pulled last week. Both hang, even though 8.2-STABLE in Feb 2012 did not hang.

First terminal:

Snapshot
Renaming from to 1
load: 0.00  cmd: zfs 57149 [tx->tx_sync_done_cv)] 104.03r 0.00u 0.00s 0% 1920k


Second:
# zfs list
load: 0.00  cmd: zfs 58403 [spa_namespace_lock] 119.06r 0.00u 0.00s 0% 1796k

--------------060109020708020504050507-- From owner-freebsd-fs@FreeBSD.ORG Mon Jun 11 10:15:09 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id E9DBE106564A for ; Mon, 11 Jun 2012 10:15:09 +0000 (UTC) (envelope-from freebsd-fs@m.gmane.org) Received: from plane.gmane.org (plane.gmane.org [80.91.229.3]) by mx1.freebsd.org (Postfix) with ESMTP id 96BEA8FC16 for ; Mon, 11 Jun 2012 10:15:09 +0000 (UTC) Received: from list by plane.gmane.org with local (Exim 4.69) (envelope-from ) id 1Se1eK-00054P-2H for freebsd-fs@freebsd.org; Mon, 11 Jun 2012 12:15:04 +0200 Received: from lara.cc.fer.hr ([161.53.72.113]) by main.gmane.org with esmtp (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Mon, 11 Jun 2012 12:15:04 +0200 Received: from ivoras by lara.cc.fer.hr with local (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Mon, 11 Jun 2012 12:15:04 +0200 X-Injected-Via-Gmane: http://gmane.org/ To: freebsd-fs@freebsd.org From: Ivan Voras Date: Mon, 11 Jun 2012 12:14:38 +0200 Lines: 47 Message-ID: References: <4FD214FB.3080507@gmail.com> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="------------enig5A93F991CDD5FF9F03D9EF9F" X-Complaints-To: usenet@dough.gmane.org X-Gmane-NNTP-Posting-Host: lara.cc.fer.hr User-Agent: Mozilla/5.0 (X11; FreeBSD amd64; rv:10.0) Gecko/20120213 Thunderbird/10.0 In-Reply-To: <4FD214FB.3080507@gmail.com> X-Enigmail-Version: 1.3.5 Subject: Re: zfs and swap working? X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Jun 2012 10:15:10 -0000 This is an OpenPGP/MIME signed message (RFC 2440 and 3156) --------------enig5A93F991CDD5FF9F03D9EF9F Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable On 08/06/2012 17:06, Volodymyr Kostyrko wrote: > Hi all. >=20 > Didn't I miss anything? Someone has fixed swap to zfs vdevs? > This is just after surviving one night trying to rebuild lang/pypy > without enough memory. Everything works fine, swap data is also > compressed and cached on cache device. It has always worked for light, non-demanding loads. As you've also described in your post, ZFS may need to do a lot of operations between when it gets data and when it writes data to the drives (you mention compression and caching, but there's also RAID, checksumming, etc) and all these operations require ZFS to allocate memory. If memory is really scarce, you can get the situation where the system tries to free memory by swapping, only to have the swapper require more memory to perform the operation. Or at least this used to be the case. Quick Googling show that Solaris has documented that swapping to ZVOLs should work - I wonder how they get around these types of problems. It looks like they can also dump to ZVOls (http://docs.oracle.com/cd/E19963-01/html/821-1448/ggrln.html). --------------enig5A93F991CDD5FF9F03D9EF9F Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.18 (FreeBSD) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAk/VxRwACgkQ/QjVBj3/HSxJvACdF/3jWb8sLjWY/UfC+BC23hqe +nkAn2eoJ3jS8C9B/HwdKxtETSFTwxy6 =hAyZ -----END PGP SIGNATURE----- --------------enig5A93F991CDD5FF9F03D9EF9F-- From owner-freebsd-fs@FreeBSD.ORG Mon Jun 11 10:16:43 2012 Return-Path: Delivered-To: freebsd-fs@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id B8AD3106566C; Mon, 11 Jun 2012 10:16:43 +0000 (UTC) (envelope-from simon@comsys.ntu-kpi.kiev.ua) Received: from comsys.kpi.ua (comsys.kpi.ua [77.47.192.42]) by mx1.freebsd.org (Postfix) with ESMTP id 2EAC58FC12; Mon, 11 Jun 2012 10:16:43 +0000 (UTC) Received: from pm513-1.comsys.kpi.ua ([10.18.52.101] helo=pm513-1.comsys.ntu-kpi.kiev.ua) by comsys.kpi.ua with esmtpsa (TLSv1:AES256-SHA:256) (Exim 4.63) (envelope-from ) id 1Se1ft-0005ie-SA; Mon, 11 Jun 2012 13:16:41 +0300 Received: by pm513-1.comsys.ntu-kpi.kiev.ua (Postfix, from userid 1001) id A405A1CC34; Mon, 11 Jun 2012 13:16:41 +0300 (EEST) Date: Mon, 11 Jun 2012 13:16:41 +0300 From: Andrey Simonenko To: Martin Birgmeier Message-ID: <20120611101641.GA33194@pm513-1.comsys.ntu-kpi.kiev.ua> References: <201205200810.q4K8A4KP087730@freefall.freebsd.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <201205200810.q4K8A4KP087730@freefall.freebsd.org> User-Agent: Mutt/1.5.21 (2010-09-15) X-Authenticated-User: simon@comsys.ntu-kpi.kiev.ua X-Authenticator: plain X-Sender-Verify: SUCCEEDED (sender exists & accepts mail) X-Exim-Version: 4.63 (build at 28-Apr-2011 07:11:12) X-Date: 2012-06-11 13:16:41 X-Connected-IP: 10.18.52.101:38310 X-Message-Linecount: 66 X-Body-Linecount: 50 X-Message-Size: 2792 X-Body-Size: 2061 Cc: freebsd-fs@FreeBSD.org, bug-followup@FreeBSD.org Subject: Re: kern/136865: [nfs] [patch] NFS exports atomic and on-the-fly atomic updates X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Jun 2012 10:16:43 -0000 On Sun, May 20, 2012 at 08:10:04AM +0000, Martin Birgmeier wrote: > > - Could you give a concise list of incompatibilities (and even > regressions if they should exist at all) of your solution compared to > the standard one? - As to the advantages, I am already convinced. :-) > This is the list of difference between "nfse -C ..." (compatible mode with mountd) and mountd: 1. All options from exports(5) are supported, except obsolete options -o, -n and -m (exports(5) mentions only -o for r/o access) and the -webnfs option. 2. The -alldirs option works as described in exports(5). Right now mountd ignores this option (it was broken almost ~5 years ago). 3. The -sec option works correctly (mountd incorrectly gives a remote system information about security flavors). 4. If some option overwrites previous option, then new option will be used Eg. "/fs host1 -ro host2", host1 will have r/w and host2 will have r/o access mode. 5. If some pathname has wrong option, duplicated address specification, then nfse will ignore all settings for this pathname. 6. If a line is not started with pathname, then nfse will ignore entire configuration. 7. The -index option for the new NFS server will be ignored, since its implementation in new and old NFS servers are different. 8. If several pathnames are given in one line, then they are not required to belong to the same file system. 9. If the -h command line option is used, then nfse will require the -p command line option as well. 10. The -2, -e, -n, -o, -r command line options are not supported, there are better solutions as command line options or configuration options. The list of differences between nfs.exports(5) and exports(5) is not given, since it will require to copy here entire documentation. Anyone can test whether nfse understands existent configurations without installing nfse and recompiling the kernel using instructions from this message: http://lists.freebsd.org/pipermail/freebsd-fs/2010-May/008421.html From owner-freebsd-fs@FreeBSD.ORG Mon Jun 11 10:20:12 2012 Return-Path: Delivered-To: freebsd-fs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 3478D1065670 for ; Mon, 11 Jun 2012 10:20:11 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id BE9FB8FC14 for ; Mon, 11 Jun 2012 10:20:11 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.5/8.14.5) with ESMTP id q5BAKBGq084614 for ; Mon, 11 Jun 2012 10:20:11 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.5/8.14.5/Submit) id q5BAKBS7084613; Mon, 11 Jun 2012 10:20:11 GMT (envelope-from gnats) Date: Mon, 11 Jun 2012 10:20:11 GMT Message-Id: <201206111020.q5BAKBS7084613@freefall.freebsd.org> To: freebsd-fs@FreeBSD.org From: Andrey Simonenko Cc: Subject: Re: kern/136865: [nfs] [patch] NFS exports atomic and on-the-fly atomic updates X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Andrey Simonenko List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Jun 2012 10:20:12 -0000 The following reply was made to PR kern/136865; it has been noted by GNATS. From: Andrey Simonenko To: Martin Birgmeier Cc: freebsd-fs@FreeBSD.org, bug-followup@FreeBSD.org Subject: Re: kern/136865: [nfs] [patch] NFS exports atomic and on-the-fly atomic updates Date: Mon, 11 Jun 2012 13:16:41 +0300 On Sun, May 20, 2012 at 08:10:04AM +0000, Martin Birgmeier wrote: > > - Could you give a concise list of incompatibilities (and even > regressions if they should exist at all) of your solution compared to > the standard one? - As to the advantages, I am already convinced. :-) > This is the list of difference between "nfse -C ..." (compatible mode with mountd) and mountd: 1. All options from exports(5) are supported, except obsolete options -o, -n and -m (exports(5) mentions only -o for r/o access) and the -webnfs option. 2. The -alldirs option works as described in exports(5). Right now mountd ignores this option (it was broken almost ~5 years ago). 3. The -sec option works correctly (mountd incorrectly gives a remote system information about security flavors). 4. If some option overwrites previous option, then new option will be used Eg. "/fs host1 -ro host2", host1 will have r/w and host2 will have r/o access mode. 5. If some pathname has wrong option, duplicated address specification, then nfse will ignore all settings for this pathname. 6. If a line is not started with pathname, then nfse will ignore entire configuration. 7. The -index option for the new NFS server will be ignored, since its implementation in new and old NFS servers are different. 8. If several pathnames are given in one line, then they are not required to belong to the same file system. 9. If the -h command line option is used, then nfse will require the -p command line option as well. 10. The -2, -e, -n, -o, -r command line options are not supported, there are better solutions as command line options or configuration options. The list of differences between nfs.exports(5) and exports(5) is not given, since it will require to copy here entire documentation. Anyone can test whether nfse understands existent configurations without installing nfse and recompiling the kernel using instructions from this message: http://lists.freebsd.org/pipermail/freebsd-fs/2010-May/008421.html From owner-freebsd-fs@FreeBSD.ORG Mon Jun 11 10:30:17 2012 Return-Path: Delivered-To: freebsd-fs@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 3DF4F106564A; Mon, 11 Jun 2012 10:30:17 +0000 (UTC) (envelope-from avg@FreeBSD.org) Received: from citadel.icyb.net.ua (citadel.icyb.net.ua [212.40.38.140]) by mx1.freebsd.org (Postfix) with ESMTP id 288B98FC1A; Mon, 11 Jun 2012 10:30:15 +0000 (UTC) Received: from porto.starpoint.kiev.ua (porto-e.starpoint.kiev.ua [212.40.38.100]) by citadel.icyb.net.ua (8.8.8p3/ICyb-2.3exp) with ESMTP id NAA26706; Mon, 11 Jun 2012 13:30:14 +0300 (EEST) (envelope-from avg@FreeBSD.org) Received: from localhost ([127.0.0.1]) by porto.starpoint.kiev.ua with esmtp (Exim 4.34 (FreeBSD)) id 1Se1t0-00039Z-81; Mon, 11 Jun 2012 13:30:14 +0300 Message-ID: <4FD5C8B5.2070802@FreeBSD.org> Date: Mon, 11 Jun 2012 13:30:13 +0300 From: Andriy Gapon User-Agent: Mozilla/5.0 (X11; FreeBSD amd64; rv:12.0) Gecko/20120503 Thunderbird/12.0.1 MIME-Version: 1.0 To: freebsd-fs@FreeBSD.org References: <9A54A14B-7DA4-48AD-8198-63A8572D3DB3@patpro.net> <4FD5743D.4030002@FreeBSD.org> In-Reply-To: <4FD5743D.4030002@FreeBSD.org> X-Enigmail-Version: 1.5pre Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit Cc: Pawel Jakub Dawidek , Matthew Seaman , patpro@patpro.net Subject: Re: [zfs] need help with a bug (PR 156781) X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Jun 2012 10:30:17 -0000 I can observer a similar problem where I can not list .zfs directory under filesystems which do not have any snapshots. I can not tell if the problem happens when all snapshots are removed or if it only happens if a filesystem doesn't have any snapshots when ZFS is initialized (a system is booted). I am not sure what's going on but a quick check with DTrace points to negative caching as a culprit. I see that cache_lookup() returns ENOENT for .zfs. -- Andriy Gapon From owner-freebsd-fs@FreeBSD.ORG Mon Jun 11 10:49:36 2012 Return-Path: Delivered-To: freebsd-fs@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 1F347106572C; Mon, 11 Jun 2012 10:49:36 +0000 (UTC) (envelope-from patpro@patpro.net) Received: from rack.patpro.net (rack.patpro.net [193.30.227.216]) by mx1.freebsd.org (Postfix) with ESMTP id CD58D8FC17; Mon, 11 Jun 2012 10:49:35 +0000 (UTC) Received: from rack.patpro.net (localhost [127.0.0.1]) by rack.patpro.net (Postfix) with ESMTP id 3D8DC1CC020; Mon, 11 Jun 2012 12:49:29 +0200 (CEST) X-Virus-Scanned: amavisd-new at patpro.net Received: from amavis-at-patpro.net ([127.0.0.1]) by rack.patpro.net (rack.patpro.net [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id FmgNvcsFi7pk; Mon, 11 Jun 2012 12:49:23 +0200 (CEST) Received: from [127.0.0.1] (localhost [127.0.0.1]) by rack.patpro.net (Postfix) with ESMTP; Mon, 11 Jun 2012 12:49:23 +0200 (CEST) Mime-Version: 1.0 (Apple Message framework v1084) Content-Type: text/plain; charset=us-ascii From: Patrick Proniewski In-Reply-To: <4FD5C8B5.2070802@FreeBSD.org> Date: Mon, 11 Jun 2012 12:49:23 +0200 Content-Transfer-Encoding: quoted-printable Message-Id: <4A4CAC48-3014-4612-8A28-6E888F4029AF@patpro.net> References: <9A54A14B-7DA4-48AD-8198-63A8572D3DB3@patpro.net> <4FD5743D.4030002@FreeBSD.org> <4FD5C8B5.2070802@FreeBSD.org> To: Andriy Gapon X-Mailer: Apple Mail (2.1084) Cc: freebsd-fs@FreeBSD.org, Pawel Jakub Dawidek , Matthew Seaman Subject: Re: [zfs] need help with a bug (PR 156781) X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Jun 2012 10:49:36 -0000 Hi,=20 On 11 juin 2012, at 12:30, Andriy Gapon wrote: > I am not sure what's going on but a quick check with DTrace points to = negative > caching as a culprit. I see that cache_lookup() returns ENOENT for = .zfs. What is the FreeBSD release? And do you experience similar freezes, or = just the listing problem? regards, patpro= From owner-freebsd-fs@FreeBSD.ORG Mon Jun 11 11:07:22 2012 Return-Path: Delivered-To: freebsd-fs@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 113D8106568B for ; Mon, 11 Jun 2012 11:07:22 +0000 (UTC) (envelope-from owner-bugmaster@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id EFBFC8FC16 for ; Mon, 11 Jun 2012 11:07:21 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.5/8.14.5) with ESMTP id q5BB7LsV053281 for ; Mon, 11 Jun 2012 11:07:21 GMT (envelope-from owner-bugmaster@FreeBSD.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.5/8.14.5/Submit) id q5BB7Lak053279 for freebsd-fs@FreeBSD.org; Mon, 11 Jun 2012 11:07:21 GMT (envelope-from owner-bugmaster@FreeBSD.org) Date: Mon, 11 Jun 2012 11:07:21 GMT Message-Id: <201206111107.q5BB7Lak053279@freefall.freebsd.org> X-Authentication-Warning: freefall.freebsd.org: gnats set sender to owner-bugmaster@FreeBSD.org using -f From: FreeBSD bugmaster To: freebsd-fs@FreeBSD.org Cc: Subject: Current problem reports assigned to freebsd-fs@FreeBSD.org X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Jun 2012 11:07:22 -0000 Note: to view an individual PR, use: http://www.freebsd.org/cgi/query-pr.cgi?pr=(number). The following is a listing of current problems submitted by FreeBSD users. These represent problem reports covering all versions including experimental development code and obsolete releases. S Tracker Resp. Description -------------------------------------------------------------------------------- o kern/168158 fs [zfs] incorrect parsing of sharenfs options in zfs (fs o kern/167979 fs [ufs] DIOCGDINFO ioctl does not work on 8.2 file syste o kern/167977 fs [smbfs] mount_smbfs results are differ when utf-8 or U o kern/167905 fs [zfs] zfs set canmount=on UNMOUNTS dataset o kern/167688 fs [fusefs] Incorrect signal handling with direct_io o kern/167685 fs [zfs] ZFS on USB drive prevents shutdown / reboot o kern/167612 fs [portalfs] The portal file system gets stuck inside po o kern/167272 fs [zfs] ZFS Disks reordering causes ZFS to pick the wron o kern/167260 fs [msdosfs] msdosfs disk was mounted the second time whe o kern/167109 fs [zfs] [panic] zfs diff kernel panic Fatal trap 9: gene o kern/167105 fs [nfs] mount_nfs can not handle source exports wiht mor o kern/167067 fs [zfs] [panic] ZFS panics the server o kern/167066 fs [zfs] ZVOLs not appearing in /dev/zvol o kern/167065 fs [zfs] boot fails when a spare is the boot disk o kern/167048 fs [nfs] [patch] RELEASE-9 crash when using ZFS+NULLFS+NF o kern/166912 fs [ufs] [panic] Panic after converting Softupdates to jo o kern/166851 fs [zfs] [hang] Copying directory from the mounted UFS di o kern/166566 fs [zfs] zfs split renders 2 disk (MBR based) mirror unbo o kern/166477 fs [nfs] NFS data corruption. o kern/165950 fs [ffs] SU+J and fsck problem o kern/165923 fs [nfs] Writing to NFS-backed mmapped files fails if flu o kern/165521 fs [zfs] [hang] livelock on 1 Gig of RAM with zfs when 31 o kern/165392 fs Multiple mkdir/rmdir fails with errno 31 o kern/165087 fs [unionfs] lock violation in unionfs o kern/164472 fs [ufs] fsck -B panics on particular data inconsistency o kern/164370 fs [zfs] zfs destroy for snapshot fails on i386 and sparc o kern/164261 fs [nullfs] [patch] fix panic with NFS served from NULLFS o kern/164256 fs [zfs] device entry for volume is not created after zfs o kern/164184 fs [ufs] [panic] Kernel panic with ufs_makeinode o kern/163801 fs [md] [request] allow mfsBSD legacy installed in 'swap' o kern/163770 fs [zfs] [hang] LOR between zfs&syncer + vnlru leading to o kern/163501 fs [nfs] NFS exporting a dir and a subdir in that dir to o kern/162944 fs [coda] Coda file system module looks broken in 9.0 o kern/162860 fs [zfs] Cannot share ZFS filesystem to hosts with a hyph o kern/162751 fs [zfs] [panic] kernel panics during file operations o kern/162591 fs [nullfs] cross-filesystem nullfs does not work as expe o kern/162519 fs [zfs] "zpool import" relies on buggy realpath() behavi o kern/162362 fs [snapshots] [panic] ufs with snapshot(s) panics when g o kern/161968 fs [zfs] [hang] renaming snapshot with -r including a zvo o kern/161897 fs [zfs] [patch] zfs partition probing causing long delay o kern/161864 fs [ufs] removing journaling from UFS partition fails on o bin/161807 fs [patch] add option for explicitly specifying metadata o kern/161579 fs [smbfs] FreeBSD sometimes panics when an smb share is o kern/161533 fs [zfs] [panic] zfs receive panic: system ioctl returnin o kern/161438 fs [zfs] [panic] recursed on non-recursive spa_namespace_ o kern/161424 fs [nullfs] __getcwd() calls fail when used on nullfs mou o kern/161280 fs [zfs] Stack overflow in gptzfsboot o kern/161205 fs [nfs] [pfsync] [regression] [build] Bug report freebsd o kern/161169 fs [zfs] [panic] ZFS causes kernel panic in dbuf_dirty o kern/161112 fs [ufs] [lor] filesystem LOR in FreeBSD 9.0-BETA3 o kern/160893 fs [zfs] [panic] 9.0-BETA2 kernel panic o kern/160860 fs [ufs] Random UFS root filesystem corruption with SU+J o kern/160801 fs [zfs] zfsboot on 8.2-RELEASE fails to boot from root-o o kern/160790 fs [fusefs] [panic] VPUTX: negative ref count with FUSE o kern/160777 fs [zfs] [hang] RAID-Z3 causes fatal hang upon scrub/impo o kern/160706 fs [zfs] zfs bootloader fails when a non-root vdev exists o kern/160591 fs [zfs] Fail to boot on zfs root with degraded raidz2 [r o kern/160410 fs [smbfs] [hang] smbfs hangs when transferring large fil o kern/160283 fs [zfs] [patch] 'zfs list' does abort in make_dataset_ha o kern/159930 fs [ufs] [panic] kernel core o kern/159402 fs [zfs][loader] symlinks cause I/O errors o kern/159357 fs [zfs] ZFS MAXNAMELEN macro has confusing name (off-by- o kern/159356 fs [zfs] [patch] ZFS NAME_ERR_DISKLIKE check is Solaris-s o kern/159351 fs [nfs] [patch] - divide by zero in mountnfs() o kern/159251 fs [zfs] [request]: add FLETCHER4 as DEDUP hash option o kern/159077 fs [zfs] Can't cd .. with latest zfs version o kern/159048 fs [smbfs] smb mount corrupts large files o kern/159045 fs [zfs] [hang] ZFS scrub freezes system o kern/158839 fs [zfs] ZFS Bootloader Fails if there is a Dead Disk o kern/158802 fs amd(8) ICMP storm and unkillable process. o kern/158231 fs [nullfs] panic on unmounting nullfs mounted over ufs o f kern/157929 fs [nfs] NFS slow read o kern/157399 fs [zfs] trouble with: mdconfig force delete && zfs strip o kern/157179 fs [zfs] zfs/dbuf.c: panic: solaris assert: arc_buf_remov o kern/156797 fs [zfs] [panic] Double panic with FreeBSD 9-CURRENT and o kern/156781 fs [zfs] zfs is losing the snapshot directory, p kern/156545 fs [ufs] mv could break UFS on SMP systems o kern/156193 fs [ufs] [hang] UFS snapshot hangs && deadlocks processes o kern/156039 fs [nullfs] [unionfs] nullfs + unionfs do not compose, re o kern/155615 fs [zfs] zfs v28 broken on sparc64 -current o kern/155587 fs [zfs] [panic] kernel panic with zfs p kern/155411 fs [regression] [8.2-release] [tmpfs]: mount: tmpfs : No o kern/155199 fs [ext2fs] ext3fs mounted as ext2fs gives I/O errors o bin/155104 fs [zfs][patch] use /dev prefix by default when importing o kern/154930 fs [zfs] cannot delete/unlink file from full volume -> EN o kern/154828 fs [msdosfs] Unable to create directories on external USB o kern/154491 fs [smbfs] smb_co_lock: recursive lock for object 1 p kern/154228 fs [md] md getting stuck in wdrain state o kern/153996 fs [zfs] zfs root mount error while kernel is not located o kern/153753 fs [zfs] ZFS v15 - grammatical error when attempting to u o kern/153716 fs [zfs] zpool scrub time remaining is incorrect o kern/153695 fs [patch] [zfs] Booting from zpool created on 4k-sector o kern/153680 fs [xfs] 8.1 failing to mount XFS partitions o kern/153520 fs [zfs] Boot from GPT ZFS root on HP BL460c G1 unstable o kern/153418 fs [zfs] [panic] Kernel Panic occurred writing to zfs vol o kern/153351 fs [zfs] locking directories/files in ZFS o bin/153258 fs [patch][zfs] creating ZVOLs requires `refreservation' s kern/153173 fs [zfs] booting from a gzip-compressed dataset doesn't w o kern/153126 fs [zfs] vdev failure, zpool=peegel type=vdev.too_small o kern/152022 fs [nfs] nfs service hangs with linux client [regression] o kern/151942 fs [zfs] panic during ls(1) zfs snapshot directory o kern/151905 fs [zfs] page fault under load in /sbin/zfs o bin/151713 fs [patch] Bug in growfs(8) with respect to 32-bit overfl o kern/151648 fs [zfs] disk wait bug o kern/151629 fs [fs] [patch] Skip empty directory entries during name o kern/151330 fs [zfs] will unshare all zfs filesystem after execute a o kern/151326 fs [nfs] nfs exports fail if netgroups contain duplicate o kern/151251 fs [ufs] Can not create files on filesystem with heavy us o kern/151226 fs [zfs] can't delete zfs snapshot o kern/151111 fs [zfs] vnodes leakage during zfs unmount o kern/150503 fs [zfs] ZFS disks are UNAVAIL and corrupted after reboot o kern/150501 fs [zfs] ZFS vdev failure vdev.bad_label on amd64 o kern/150390 fs [zfs] zfs deadlock when arcmsr reports drive faulted o kern/150336 fs [nfs] mountd/nfsd became confused; refused to reload n o kern/149208 fs mksnap_ffs(8) hang/deadlock o kern/149173 fs [patch] [zfs] make OpenSolaris installa o kern/149015 fs [zfs] [patch] misc fixes for ZFS code to build on Glib o kern/149014 fs [zfs] [patch] declarations in ZFS libraries/utilities o kern/149013 fs [zfs] [patch] make ZFS makefiles use the libraries fro o kern/148504 fs [zfs] ZFS' zpool does not allow replacing drives to be o kern/148490 fs [zfs]: zpool attach - resilver bidirectionally, and re o kern/148368 fs [zfs] ZFS hanging forever on 8.1-PRERELEASE o kern/148138 fs [zfs] zfs raidz pool commands freeze o kern/147903 fs [zfs] [panic] Kernel panics on faulty zfs device o kern/147881 fs [zfs] [patch] ZFS "sharenfs" doesn't allow different " o kern/147560 fs [zfs] [boot] Booting 8.1-PRERELEASE raidz system take o kern/147420 fs [ufs] [panic] ufs_dirbad, nullfs, jail panic (corrupt o kern/146941 fs [zfs] [panic] Kernel Double Fault - Happens constantly o kern/146786 fs [zfs] zpool import hangs with checksum errors o kern/146708 fs [ufs] [panic] Kernel panic in softdep_disk_write_compl o kern/146528 fs [zfs] Severe memory leak in ZFS on i386 o kern/146502 fs [nfs] FreeBSD 8 NFS Client Connection to Server s kern/145712 fs [zfs] cannot offline two drives in a raidz2 configurat o kern/145411 fs [xfs] [panic] Kernel panics shortly after mounting an f bin/145309 fs bsdlabel: Editing disk label invalidates the whole dev o kern/145272 fs [zfs] [panic] Panic during boot when accessing zfs on o kern/145246 fs [ufs] dirhash in 7.3 gratuitously frees hashes when it o kern/145238 fs [zfs] [panic] kernel panic on zpool clear tank o kern/145229 fs [zfs] Vast differences in ZFS ARC behavior between 8.0 o kern/145189 fs [nfs] nfsd performs abysmally under load o kern/144929 fs [ufs] [lor] vfs_bio.c + ufs_dirhash.c p kern/144447 fs [zfs] sharenfs fsunshare() & fsshare_main() non functi o kern/144416 fs [panic] Kernel panic on online filesystem optimization s kern/144415 fs [zfs] [panic] kernel panics on boot after zfs crash o kern/144234 fs [zfs] Cannot boot machine with recent gptzfsboot code o kern/143825 fs [nfs] [panic] Kernel panic on NFS client o bin/143572 fs [zfs] zpool(1): [patch] The verbose output from iostat o kern/143212 fs [nfs] NFSv4 client strange work ... o kern/143184 fs [zfs] [lor] zfs/bufwait LOR o kern/142878 fs [zfs] [vfs] lock order reversal o kern/142597 fs [ext2fs] ext2fs does not work on filesystems with real o kern/142489 fs [zfs] [lor] allproc/zfs LOR o kern/142466 fs Update 7.2 -> 8.0 on Raid 1 ends with screwed raid [re o kern/142306 fs [zfs] [panic] ZFS drive (from OSX Leopard) causes two o kern/142068 fs [ufs] BSD labels are got deleted spontaneously o kern/141897 fs [msdosfs] [panic] Kernel panic. msdofs: file name leng o kern/141463 fs [nfs] [panic] Frequent kernel panics after upgrade fro o kern/141305 fs [zfs] FreeBSD ZFS+sendfile severe performance issues ( o kern/141091 fs [patch] [nullfs] fix panics with DIAGNOSTIC enabled o kern/141086 fs [nfs] [panic] panic("nfs: bioread, not dir") on FreeBS o kern/141010 fs [zfs] "zfs scrub" fails when backed by files in UFS2 o kern/140888 fs [zfs] boot fail from zfs root while the pool resilveri o kern/140661 fs [zfs] [patch] /boot/loader fails to work on a GPT/ZFS- o kern/140640 fs [zfs] snapshot crash o kern/140068 fs [smbfs] [patch] smbfs does not allow semicolon in file o kern/139725 fs [zfs] zdb(1) dumps core on i386 when examining zpool c o kern/139715 fs [zfs] vfs.numvnodes leak on busy zfs p bin/139651 fs [nfs] mount(8): read-only remount of NFS volume does n o kern/139564 fs [zfs] [panic] 8.0-RC1 - Fatal trap 12 at end of shutdo o kern/139407 fs [smbfs] [panic] smb mount causes system crash if remot o kern/138662 fs [panic] ffs_blkfree: freeing free block o kern/138421 fs [ufs] [patch] remove UFS label limitations o kern/138202 fs mount_msdosfs(1) see only 2Gb o kern/136968 fs [ufs] [lor] ufs/bufwait/ufs (open) o kern/136945 fs [ufs] [lor] filedesc structure/ufs (poll) o kern/136944 fs [ffs] [lor] bufwait/snaplk (fsync) o kern/136873 fs [ntfs] Missing directories/files on NTFS volume o kern/136865 fs [nfs] [patch] NFS exports atomic and on-the-fly atomic p kern/136470 fs [nfs] Cannot mount / in read-only, over NFS o kern/135546 fs [zfs] zfs.ko module doesn't ignore zpool.cache filenam o kern/135469 fs [ufs] [panic] kernel crash on md operation in ufs_dirb o kern/135050 fs [zfs] ZFS clears/hides disk errors on reboot o kern/134491 fs [zfs] Hot spares are rather cold... o kern/133676 fs [smbfs] [panic] umount -f'ing a vnode-based memory dis o kern/132960 fs [ufs] [panic] panic:ffs_blkfree: freeing free frag o kern/132397 fs reboot causes filesystem corruption (failure to sync b o kern/132331 fs [ufs] [lor] LOR ufs and syncer o kern/132237 fs [msdosfs] msdosfs has problems to read MSDOS Floppy o kern/132145 fs [panic] File System Hard Crashes o kern/131441 fs [unionfs] [nullfs] unionfs and/or nullfs not combineab o kern/131360 fs [nfs] poor scaling behavior of the NFS server under lo o kern/131342 fs [nfs] mounting/unmounting of disks causes NFS to fail o bin/131341 fs makefs: error "Bad file descriptor" on the mount poin o kern/130920 fs [msdosfs] cp(1) takes 100% CPU time while copying file o kern/130210 fs [nullfs] Error by check nullfs o kern/129760 fs [nfs] after 'umount -f' of a stale NFS share FreeBSD l o kern/129488 fs [smbfs] Kernel "bug" when using smbfs in smbfs_smb.c: o kern/129231 fs [ufs] [patch] New UFS mount (norandom) option - mostly o kern/129152 fs [panic] non-userfriendly panic when trying to mount(8) o kern/127787 fs [lor] [ufs] Three LORs: vfslock/devfs/vfslock, ufs/vfs o bin/127270 fs fsck_msdosfs(8) may crash if BytesPerSec is zero o kern/127029 fs [panic] mount(8): trying to mount a write protected zi o kern/126287 fs [ufs] [panic] Kernel panics while mounting an UFS file o kern/125895 fs [ffs] [panic] kernel: panic: ffs_blkfree: freeing free s kern/125738 fs [zfs] [request] SHA256 acceleration in ZFS o kern/123939 fs [msdosfs] corrupts new files o kern/122380 fs [ffs] ffs_valloc:dup alloc (Soekris 4801/7.0/USB Flash o bin/122172 fs [fs]: amd(8) automount daemon dies on 6.3-STABLE i386, o bin/121898 fs [nullfs] pwd(1)/getcwd(2) fails with Permission denied o bin/121072 fs [smbfs] mount_smbfs(8) cannot normally convert the cha o kern/120483 fs [ntfs] [patch] NTFS filesystem locking changes o kern/120482 fs [ntfs] [patch] Sync style changes between NetBSD and F o kern/118912 fs [2tb] disk sizing/geometry problem with large array o kern/118713 fs [minidump] [patch] Display media size required for a k o kern/118318 fs [nfs] NFS server hangs under special circumstances o bin/118249 fs [ufs] mv(1): moving a directory changes its mtime o kern/118126 fs [nfs] [patch] Poor NFS server write performance o kern/118107 fs [ntfs] [panic] Kernel panic when accessing a file at N o kern/117954 fs [ufs] dirhash on very large directories blocks the mac o bin/117315 fs [smbfs] mount_smbfs(8) and related options can't mount o kern/117158 fs [zfs] zpool scrub causes panic if geli vdevs detach on o bin/116980 fs [msdosfs] [patch] mount_msdosfs(8) resets some flags f o conf/116931 fs lack of fsck_cd9660 prevents mounting iso images with o kern/116583 fs [ffs] [hang] System freezes for short time when using o bin/115361 fs [zfs] mount(8) gets into a state where it won't set/un o kern/114955 fs [cd9660] [patch] [request] support for mask,dirmask,ui o kern/114847 fs [ntfs] [patch] [request] dirmask support for NTFS ala o kern/114676 fs [ufs] snapshot creation panics: snapacct_ufs2: bad blo o bin/114468 fs [patch] [request] add -d option to umount(8) to detach o kern/113852 fs [smbfs] smbfs does not properly implement DFS referral o bin/113838 fs [patch] [request] mount(8): add support for relative p o bin/113049 fs [patch] [request] make quot(8) use getopt(3) and show o kern/112658 fs [smbfs] [patch] smbfs and caching problems (resolves b o kern/111843 fs [msdosfs] Long Names of files are incorrectly created o kern/111782 fs [ufs] dump(8) fails horribly for large filesystems s bin/111146 fs [2tb] fsck(8) fails on 6T filesystem o bin/107829 fs [2TB] fdisk(8): invalid boundary checking in fdisk / w o kern/106107 fs [ufs] left-over fsck_snapshot after unfinished backgro o kern/104406 fs [ufs] Processes get stuck in "ufs" state under persist o kern/104133 fs [ext2fs] EXT2FS module corrupts EXT2/3 filesystems o kern/103035 fs [ntfs] Directories in NTFS mounted disc images appear o kern/101324 fs [smbfs] smbfs sometimes not case sensitive when it's s o kern/99290 fs [ntfs] mount_ntfs ignorant of cluster sizes s bin/97498 fs [request] newfs(8) has no option to clear the first 12 o kern/97377 fs [ntfs] [patch] syntax cleanup for ntfs_ihash.c o kern/95222 fs [cd9660] File sections on ISO9660 level 3 CDs ignored o kern/94849 fs [ufs] rename on UFS filesystem is not atomic o bin/94810 fs fsck(8) incorrectly reports 'file system marked clean' o kern/94769 fs [ufs] Multiple file deletions on multi-snapshotted fil o kern/94733 fs [smbfs] smbfs may cause double unlock o kern/93942 fs [vfs] [patch] panic: ufs_dirbad: bad dir (patch from D o kern/92272 fs [ffs] [hang] Filling a filesystem while creating a sna o kern/91134 fs [smbfs] [patch] Preserve access and modification time a kern/90815 fs [smbfs] [patch] SMBFS with character conversions somet o kern/88657 fs [smbfs] windows client hang when browsing a samba shar o kern/88555 fs [panic] ffs_blkfree: freeing free frag on AMD 64 o kern/88266 fs [smbfs] smbfs does not implement UIO_NOCOPY and sendfi o bin/87966 fs [patch] newfs(8): introduce -A flag for newfs to enabl o kern/87859 fs [smbfs] System reboot while umount smbfs. o kern/86587 fs [msdosfs] rm -r /PATH fails with lots of small files o bin/85494 fs fsck_ffs: unchecked use of cg_inosused macro etc. o kern/80088 fs [smbfs] Incorrect file time setting on NTFS mounted vi o bin/74779 fs Background-fsck checks one filesystem twice and omits o kern/73484 fs [ntfs] Kernel panic when doing `ls` from the client si o bin/73019 fs [ufs] fsck_ufs(8) cannot alloc 607016868 bytes for ino o kern/71774 fs [ntfs] NTFS cannot "see" files on a WinXP filesystem o bin/70600 fs fsck(8) throws files away when it can't grow lost+foun o kern/68978 fs [panic] [ufs] crashes with failing hard disk, loose po o kern/65920 fs [nwfs] Mounted Netware filesystem behaves strange o kern/65901 fs [smbfs] [patch] smbfs fails fsx write/truncate-down/tr o kern/61503 fs [smbfs] mount_smbfs does not work as non-root o kern/55617 fs [smbfs] Accessing an nsmb-mounted drive via a smb expo o kern/51685 fs [hang] Unbounded inode allocation causes kernel to loc o kern/36566 fs [smbfs] System reboot with dead smb mount and umount o bin/27687 fs fsck(8) wrapper is not properly passing options to fsc o kern/18874 fs [2TB] 32bit NFS servers export wrong negative values t 276 problems total. From owner-freebsd-fs@FreeBSD.ORG Mon Jun 11 13:52:10 2012 Return-Path: Delivered-To: freebsd-fs@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id C43661065673; Mon, 11 Jun 2012 13:52:10 +0000 (UTC) (envelope-from patpro@patpro.net) Received: from rack.patpro.net (rack.patpro.net [193.30.227.216]) by mx1.freebsd.org (Postfix) with ESMTP id 81BA08FC19; Mon, 11 Jun 2012 13:52:10 +0000 (UTC) Received: from rack.patpro.net (localhost [127.0.0.1]) by rack.patpro.net (Postfix) with ESMTP id B21301CC020; Mon, 11 Jun 2012 15:52:09 +0200 (CEST) X-Virus-Scanned: amavisd-new at patpro.net Received: from amavis-at-patpro.net ([127.0.0.1]) by rack.patpro.net (rack.patpro.net [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id uaw3_9RC2Qwt; Mon, 11 Jun 2012 15:52:04 +0200 (CEST) Received: from [127.0.0.1] (localhost [127.0.0.1]) by rack.patpro.net (Postfix) with ESMTP; Mon, 11 Jun 2012 15:52:04 +0200 (CEST) Mime-Version: 1.0 (Apple Message framework v1084) Content-Type: text/plain; charset=us-ascii From: Patrick Proniewski In-Reply-To: <4FD5743D.4030002@FreeBSD.org> Date: Mon, 11 Jun 2012 15:52:03 +0200 Content-Transfer-Encoding: quoted-printable Message-Id: <672674FB-5E5F-4C4B-834A-07CD77A07478@patpro.net> References: <9A54A14B-7DA4-48AD-8198-63A8572D3DB3@patpro.net> <4FD5743D.4030002@FreeBSD.org> To: Matthew Seaman X-Mailer: Apple Mail (2.1084) Cc: freebsd-fs@FreeBSD.org Subject: Re: [zfs] need help with a bug (PR 156781) X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Jun 2012 13:52:10 -0000 On 11 juin 2012, at 06:29, Matthew Seaman wrote: > On 11/06/2012 00:36, Mark Felder wrote: >> FreeBSD 8.1 and 8.2 are actually quite old these days. I don't think >> this bug is reproducible on 8.3 or 9.0. Can you upgrade and report = back? >=20 > I'm seeing exactly this on stable/9. Seems to be triggered by doing > certain IO patterns -- so csup of the ports cvs repo and subsequent > checkout will cause the effect, but direct csup of the ports tree = doesn't. Ok, I'm not exactly relieved the bug hits also 9.0, but it's good news I = won't have to plan a remote upgrade of FreeBSD and ZFS over ssh. I = master the process, having done FreeBSD upgrades over ssh since 5.x = (either sources and binary way), but the less I do it, the better I = feel. > This is using a zpool created under 8.0-RELEASE and subsequently > updated. mine have been created under 8.1 and 8.2 respectively, as far as I = remember (btw, is there any way to list the change history of a system, = other than keeping manual trace of every updates/upgrades?). regards, patpro From owner-freebsd-fs@FreeBSD.ORG Mon Jun 11 14:17:27 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id BC87510656B1 for ; Mon, 11 Jun 2012 14:17:27 +0000 (UTC) (envelope-from ronald-freebsd8@klop.yi.org) Received: from smarthost1.greenhost.nl (smarthost1.greenhost.nl [195.190.28.78]) by mx1.freebsd.org (Postfix) with ESMTP id 60A718FC19 for ; Mon, 11 Jun 2012 14:17:27 +0000 (UTC) Received: from smtp.greenhost.nl ([213.108.104.138]) by smarthost1.greenhost.nl with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.69) (envelope-from ) id 1Se5Qq-0007gG-2J for freebsd-fs@freebsd.org; Mon, 11 Jun 2012 16:17:24 +0200 Received: from [81.21.138.17] (helo=ronaldradial.versatec.local) by smtp.greenhost.nl with esmtpsa (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.72) (envelope-from ) id 1Se5Qq-0000u1-CW for freebsd-fs@freebsd.org; Mon, 11 Jun 2012 16:17:24 +0200 Content-Type: text/plain; charset=us-ascii; format=flowed; delsp=yes To: freebsd-fs@freebsd.org References: <9A54A14B-7DA4-48AD-8198-63A8572D3DB3@patpro.net> <4FD5743D.4030002@FreeBSD.org> <672674FB-5E5F-4C4B-834A-07CD77A07478@patpro.net> Date: Mon, 11 Jun 2012 16:17:22 +0200 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: "Ronald Klop" Message-ID: In-Reply-To: <672674FB-5E5F-4C4B-834A-07CD77A07478@patpro.net> User-Agent: Opera Mail/11.64 (Win32) X-Virus-Scanned: by clamav at smarthost1.samage.net X-Spam-Level: / X-Spam-Score: -0.2 X-Spam-Status: No, score=-0.2 required=5.0 tests=BAYES_40 autolearn=disabled version=3.2.5 X-Scan-Signature: 0ccaee305be983877c9e38c09cbf8ec4 Subject: Re: [zfs] need help with a bug (PR 156781) X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Jun 2012 14:17:27 -0000 On Mon, 11 Jun 2012 15:52:03 +0200, Patrick Proniewski wrote: > On 11 juin 2012, at 06:29, Matthew Seaman wrote: > >> On 11/06/2012 00:36, Mark Felder wrote: >>> FreeBSD 8.1 and 8.2 are actually quite old these days. I don't think >>> this bug is reproducible on 8.3 or 9.0. Can you upgrade and report >>> back? >> >> I'm seeing exactly this on stable/9. Seems to be triggered by doing >> certain IO patterns -- so csup of the ports cvs repo and subsequent >> checkout will cause the effect, but direct csup of the ports tree >> doesn't. > > Ok, I'm not exactly relieved the bug hits also 9.0, but it's good news I > won't have to plan a remote upgrade of FreeBSD and ZFS over ssh. I > master the process, having done FreeBSD upgrades over ssh since 5.x > (either sources and binary way), but the less I do it, the better I feel. > >> This is using a zpool created under 8.0-RELEASE and subsequently >> updated. > > mine have been created under 8.1 and 8.2 respectively, as far as I > remember (btw, is there any way to list the change history of a system, > other than keeping manual trace of every updates/upgrades?). zpool history > regards, > patpro From owner-freebsd-fs@FreeBSD.ORG Mon Jun 11 14:25:52 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id F0742106566B for ; Mon, 11 Jun 2012 14:25:51 +0000 (UTC) (envelope-from andrnils@gmail.com) Received: from mail-bk0-f54.google.com (mail-bk0-f54.google.com [209.85.214.54]) by mx1.freebsd.org (Postfix) with ESMTP id 6FEAB8FC19 for ; Mon, 11 Jun 2012 14:25:51 +0000 (UTC) Received: by mail-bk0-f54.google.com with SMTP id i18so4461880bkv.13 for ; Mon, 11 Jun 2012 07:25:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=cwNjUsG/qnZrAwQbJhuneuNEJDswfeozgib6vJ/k5Kk=; b=Tt3SCHgGSnXdFQRHYNP05SLoL2MNZaMlal8kBkQgYsdrgl0EexcAk9qffbxeVC5FK7 4F1G0j00Ffab7ZVBfvGHPU8oalTpbHiLXPhmQktWwDpCrCGI+ludKb7yCpKjXN6DzTcr CZ46qqWQq1DyG3rRrGpRo/zBqeoAM5eOsL/ydVkhuuVwCh66e/6G5nd6W7kpjC6JX7TH vkW9Sob5gXi8Xt1nHZ5CA3qG3LIOd0bK1Lr7HkU+RVDDPZyo43LgrfKXFKg/MoJ45fxL Wlc5xuIEe4NQSHeOuBj4dx8l86uU2UEFg4Ml12EQ0/4fTqbPNQyG0hySuBzorTbJfWsf ZF0Q== MIME-Version: 1.0 Received: by 10.205.133.13 with SMTP id hw13mr10288931bkc.30.1339424750879; Mon, 11 Jun 2012 07:25:50 -0700 (PDT) Received: by 10.204.100.83 with HTTP; Mon, 11 Jun 2012 07:25:50 -0700 (PDT) In-Reply-To: References: <9A54A14B-7DA4-48AD-8198-63A8572D3DB3@patpro.net> <4FD5743D.4030002@FreeBSD.org> <672674FB-5E5F-4C4B-834A-07CD77A07478@patpro.net> Date: Mon, 11 Jun 2012 16:25:50 +0200 Message-ID: From: Andreas Nilsson To: Ronald Klop Content-Type: text/plain; charset=ISO-8859-1 X-Content-Filtered-By: Mailman/MimeDel 2.1.5 Cc: freebsd-fs@freebsd.org Subject: Re: [zfs] need help with a bug (PR 156781) X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Jun 2012 14:25:52 -0000 On Mon, Jun 11, 2012 at 4:17 PM, Ronald Klop wrote: > On Mon, 11 Jun 2012 15:52:03 +0200, Patrick Proniewski > wrote: > > On 11 juin 2012, at 06:29, Matthew Seaman wrote: >> >> On 11/06/2012 00:36, Mark Felder wrote: >>> >>>> FreeBSD 8.1 and 8.2 are actually quite old these days. I don't think >>>> this bug is reproducible on 8.3 or 9.0. Can you upgrade and report back? >>>> >>> >>> I'm seeing exactly this on stable/9. Seems to be triggered by doing >>> certain IO patterns -- so csup of the ports cvs repo and subsequent >>> checkout will cause the effect, but direct csup of the ports tree >>> doesn't. >>> >> >> Ok, I'm not exactly relieved the bug hits also 9.0, but it's good news I >> won't have to plan a remote upgrade of FreeBSD and ZFS over ssh. I master >> the process, having done FreeBSD upgrades over ssh since 5.x (either >> sources and binary way), but the less I do it, the better I feel. >> >> This is using a zpool created under 8.0-RELEASE and subsequently >>> updated. >>> >> >> mine have been created under 8.1 and 8.2 respectively, as far as I >> remember (btw, is there any way to list the change history of a system, >> other than keeping manual trace of every updates/upgrades?). >> > > zpool history > > Just out of interest: did you upgrade pool as part of 8->9 update, ie zpool upgrade? /Andreas > > > regards, >> patpro >> > ______________________________**_________________ > freebsd-fs@freebsd.org mailing list > http://lists.freebsd.org/**mailman/listinfo/freebsd-fs > To unsubscribe, send any mail to "freebsd-fs-unsubscribe@**freebsd.org > " > From owner-freebsd-fs@FreeBSD.ORG Mon Jun 11 15:15:36 2012 Return-Path: Delivered-To: freebsd-fs@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 6182C1065673 for ; Mon, 11 Jun 2012 15:15:36 +0000 (UTC) (envelope-from matthew@FreeBSD.org) Received: from smtp.infracaninophile.co.uk (smtp6.infracaninophile.co.uk [IPv6:2001:8b0:151:1:3cd3:cd67:fafa:3d78]) by mx1.freebsd.org (Postfix) with ESMTP id C09C98FC1B for ; Mon, 11 Jun 2012 15:15:35 +0000 (UTC) Received: from seedling.black-earth.co.uk (seedling.black-earth.co.uk [81.187.76.163]) (authenticated bits=0) by smtp.infracaninophile.co.uk (8.14.5/8.14.5) with ESMTP id q5BFFVkD082239 (version=TLSv1/SSLv3 cipher=DHE-RSA-CAMELLIA256-SHA bits=256 verify=NO); Mon, 11 Jun 2012 16:15:32 +0100 (BST) (envelope-from matthew@FreeBSD.org) X-DKIM: OpenDKIM Filter v2.5.2 smtp.infracaninophile.co.uk q5BFFVkD082239 Authentication-Results: smtp.infracaninophile.co.uk/q5BFFVkD082239; dkim=none (no signature); dkim-adsp=none Message-ID: <4FD60B86.3060809@FreeBSD.org> Date: Mon, 11 Jun 2012 16:15:18 +0100 From: Matthew Seaman User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:13.0) Gecko/20120601 Thunderbird/13.0 MIME-Version: 1.0 To: Patrick Proniewski References: <9A54A14B-7DA4-48AD-8198-63A8572D3DB3@patpro.net> <4FD5743D.4030002@FreeBSD.org> <672674FB-5E5F-4C4B-834A-07CD77A07478@patpro.net> In-Reply-To: <672674FB-5E5F-4C4B-834A-07CD77A07478@patpro.net> X-Enigmail-Version: 1.4.2 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="------------enigD9093E84C1476162C17A9857" X-Virus-Scanned: clamav-milter 0.97.4 at lucid-nonsense.infracaninophile.co.uk X-Virus-Status: Clean X-Spam-Status: No, score=-2.7 required=5.0 tests=ALL_TRUSTED,AWL,BAYES_00 autolearn=ham version=3.3.2 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on lucid-nonsense.infracaninophile.co.uk Cc: freebsd-fs@FreeBSD.org Subject: Re: [zfs] need help with a bug (PR 156781) X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Jun 2012 15:15:36 -0000 This is an OpenPGP/MIME signed message (RFC 2440 and 3156) --------------enigD9093E84C1476162C17A9857 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable On 11/06/2012 14:52, Patrick Proniewski wrote: > mine have been created under 8.1 and 8.2 respectively, as far as I > remember (btw, is there any way to list the change history of a > system, other than keeping manual trace of every updates/upgrades?). # zpool history zroot History for 'zroot': 2010-05-14.20:31:21 zpool create zroot mirror /dev/gpt/disk0 /dev/gpt/dis= k2 2010-05-14.20:31:43 zpool set bootfs=3Dzroot zroot [...etc...] Cheers, Matthew --=20 Dr Matthew J Seaman MA, D.Phil. PGP: http://www.infracaninophile.co.uk/pgpkey --------------enigD9093E84C1476162C17A9857 Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG/MacGPG2 v2.0.16 (Darwin) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAk/WC5MACgkQ8Mjk52CukIzKswCfVrNGq/nsZSa2aP5It7zKNg+Y /SgAnjVX+qml551/Ook01AM49spTdGSD =AEtd -----END PGP SIGNATURE----- --------------enigD9093E84C1476162C17A9857-- From owner-freebsd-fs@FreeBSD.ORG Mon Jun 11 16:05:46 2012 Return-Path: Delivered-To: freebsd-fs@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 4CC5D1065670; Mon, 11 Jun 2012 16:05:45 +0000 (UTC) (envelope-from patpro@patpro.net) Received: from rack.patpro.net (rack.patpro.net [193.30.227.216]) by mx1.freebsd.org (Postfix) with ESMTP id 0897D8FC15; Mon, 11 Jun 2012 16:05:45 +0000 (UTC) Received: from rack.patpro.net (localhost [127.0.0.1]) by rack.patpro.net (Postfix) with ESMTP id 34BF01CC020; Mon, 11 Jun 2012 18:05:44 +0200 (CEST) X-Virus-Scanned: amavisd-new at patpro.net Received: from amavis-at-patpro.net ([127.0.0.1]) by rack.patpro.net (rack.patpro.net [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id EmOpj8rUAK3q; Mon, 11 Jun 2012 18:05:39 +0200 (CEST) Received: from [127.0.0.1] (localhost [127.0.0.1]) by rack.patpro.net (Postfix) with ESMTP; Mon, 11 Jun 2012 18:05:39 +0200 (CEST) Mime-Version: 1.0 (Apple Message framework v1084) Content-Type: text/plain; charset=us-ascii From: Patrick Proniewski In-Reply-To: <4FD60B86.3060809@FreeBSD.org> Date: Mon, 11 Jun 2012 18:05:38 +0200 Content-Transfer-Encoding: quoted-printable Message-Id: <4688C147-8819-4E34-8D5C-F630E3F26BE2@patpro.net> References: <9A54A14B-7DA4-48AD-8198-63A8572D3DB3@patpro.net> <4FD5743D.4030002@FreeBSD.org> <672674FB-5E5F-4C4B-834A-07CD77A07478@patpro.net> <4FD60B86.3060809@FreeBSD.org> To: Matthew Seaman X-Mailer: Apple Mail (2.1084) Cc: freebsd-fs@FreeBSD.org Subject: Re: [zfs] need help with a bug (PR 156781) X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Jun 2012 16:05:46 -0000 On 11 juin 2012, at 17:15, Matthew Seaman wrote: > On 11/06/2012 14:52, Patrick Proniewski wrote: >> mine have been created under 8.1 and 8.2 respectively, as far as I >> remember (btw, is there any way to list the change history of a >> system, other than keeping manual trace of every updates/upgrades?). >=20 > # zpool history zroot > History for 'zroot': > 2010-05-14.20:31:21 zpool create zroot mirror /dev/gpt/disk0 = /dev/gpt/disk2 > 2010-05-14.20:31:43 zpool set bootfs=3Dzroot zroot > [...etc...] I know zpool history, I was refering to something more "system-wide", = keeping track of updates and upgrades of FreeBSD. I use freebsd-update = for 1 or 2 years now, but can't find a proper log file. The purpose = would be to know for sure what release was installed when I created my = zfs pools. patpro From owner-freebsd-fs@FreeBSD.ORG Mon Jun 11 18:40:11 2012 Return-Path: Delivered-To: freebsd-fs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 21BFF1065677 for ; Mon, 11 Jun 2012 18:40:11 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id E7E3B8FC16 for ; Mon, 11 Jun 2012 18:40:10 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.5/8.14.5) with ESMTP id q5BIeAtb087609 for ; Mon, 11 Jun 2012 18:40:10 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.5/8.14.5/Submit) id q5BIeAVp087608; Mon, 11 Jun 2012 18:40:10 GMT (envelope-from gnats) Date: Mon, 11 Jun 2012 18:40:10 GMT Message-Id: <201206111840.q5BIeAVp087608@freefall.freebsd.org> To: freebsd-fs@FreeBSD.org From: Mateusz Guzik Cc: Subject: Re: kern/161424: [nullfs] __getcwd() calls fail when used on nullfs mount X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Mateusz Guzik List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Jun 2012 18:40:11 -0000 The following reply was made to PR kern/161424; it has been noted by GNATS. From: Mateusz Guzik To: bug-followup@FreeBSD.org, v.haisman@sh.cvut.cz Cc: Subject: Re: kern/161424: [nullfs] __getcwd() calls fail when used on nullfs mount Date: Mon, 11 Jun 2012 20:37:10 +0200 Hi, are you able to reproduce this problem on FreeBSD 9.0? Thanks, -- Mateusz Guzik From owner-freebsd-fs@FreeBSD.ORG Mon Jun 11 20:46:08 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 89B491065674 for ; Mon, 11 Jun 2012 20:46:08 +0000 (UTC) (envelope-from kostikbel@gmail.com) Received: from mail.zoral.com.ua (mx0.zoral.com.ua [91.193.166.200]) by mx1.freebsd.org (Postfix) with ESMTP id 0743C8FC1C for ; Mon, 11 Jun 2012 20:46:07 +0000 (UTC) Received: from skuns.kiev.zoral.com.ua (localhost [127.0.0.1]) by mail.zoral.com.ua (8.14.2/8.14.2) with ESMTP id q5BKk229048074; Mon, 11 Jun 2012 23:46:02 +0300 (EEST) (envelope-from kostikbel@gmail.com) Received: from deviant.kiev.zoral.com.ua (kostik@localhost [127.0.0.1]) by deviant.kiev.zoral.com.ua (8.14.5/8.14.5) with ESMTP id q5BKk1id050873; Mon, 11 Jun 2012 23:46:01 +0300 (EEST) (envelope-from kostikbel@gmail.com) Received: (from kostik@localhost) by deviant.kiev.zoral.com.ua (8.14.5/8.14.5/Submit) id q5BKk1os050872; Mon, 11 Jun 2012 23:46:01 +0300 (EEST) (envelope-from kostikbel@gmail.com) X-Authentication-Warning: deviant.kiev.zoral.com.ua: kostik set sender to kostikbel@gmail.com using -f Date: Mon, 11 Jun 2012 23:46:01 +0300 From: Konstantin Belousov To: Mateusz Guzik Message-ID: <20120611204601.GI2337@deviant.kiev.zoral.com.ua> References: <201206111840.q5BIeAVp087608@freefall.freebsd.org> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="6b3yLyRKT1M6kiA0" Content-Disposition: inline In-Reply-To: <201206111840.q5BIeAVp087608@freefall.freebsd.org> User-Agent: Mutt/1.4.2.3i X-Virus-Scanned: clamav-milter 0.95.2 at skuns.kiev.zoral.com.ua X-Virus-Status: Clean X-Spam-Status: No, score=-4.0 required=5.0 tests=ALL_TRUSTED,AWL,BAYES_00 autolearn=ham version=3.2.5 X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on skuns.kiev.zoral.com.ua Cc: freebsd-fs@freebsd.org Subject: Re: kern/161424: [nullfs] __getcwd() calls fail when used on nullfs mount X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Jun 2012 20:46:08 -0000 --6b3yLyRKT1M6kiA0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Mon, Jun 11, 2012 at 06:40:10PM +0000, Mateusz Guzik wrote: > The following reply was made to PR kern/161424; it has been noted by GNAT= S. >=20 > From: Mateusz Guzik > To: bug-followup@FreeBSD.org, v.haisman@sh.cvut.cz > Cc: =20 > Subject: Re: kern/161424: [nullfs] __getcwd() calls fail when used on > nullfs mount > Date: Mon, 11 Jun 2012 20:37:10 +0200 >=20 > Hi, > =20 > are you able to reproduce this problem on FreeBSD 9.0? It shall be reproducable on 9.0. Required changes to VOP_VPTOCNP() were merged sometime after 9.0 was released. See r227697. --6b3yLyRKT1M6kiA0 Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (FreeBSD) iEYEARECAAYFAk/WWQgACgkQC3+MBN1Mb4hEbwCdFAvj5w9Y5kfn2oFvbFVTRn4m FkkAoNSStk2wrwp74Z9U3otxLVUGrWj6 =SwFi -----END PGP SIGNATURE----- --6b3yLyRKT1M6kiA0-- From owner-freebsd-fs@FreeBSD.ORG Tue Jun 12 05:40:08 2012 Return-Path: Delivered-To: freebsd-fs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id A18A3106566B for ; Tue, 12 Jun 2012 05:40:08 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 823358FC21 for ; Tue, 12 Jun 2012 05:40:08 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.5/8.14.5) with ESMTP id q5C5e8Cx017072 for ; Tue, 12 Jun 2012 05:40:08 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.5/8.14.5/Submit) id q5C5e8Bc017067; Tue, 12 Jun 2012 05:40:08 GMT (envelope-from gnats) Date: Tue, 12 Jun 2012 05:40:08 GMT Message-Id: <201206120540.q5C5e8Bc017067@freefall.freebsd.org> To: freebsd-fs@FreeBSD.org From: Bryan Drewery Cc: Subject: Re: kern/167905: [zfs] zfs set canmount=on UNMOUNTS dataset X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Bryan Drewery List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 12 Jun 2012 05:40:08 -0000 The following reply was made to PR kern/167905; it has been noted by GNATS. From: Bryan Drewery To: bug-followup@FreeBSD.org, vermaden@interia.pl Cc: Pawel Jakub Dawidek , mm@freebsd.org Subject: Re: kern/167905: [zfs] zfs set canmount=on UNMOUNTS dataset Date: Tue, 12 Jun 2012 00:35:58 -0500 This is a multi-part message in MIME format. --------------040108060500020307070404 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Attached is a patch to fix setting 'zfs set canmount=on' to not cause a remount if the dataset is *already mounted*. This fixes the issue reported here, as well as here http://lists.freebsd.org/pipermail/freebsd-fs/2012-May/014241.html $ cd /usr/src/cddl $ patch -p1 < patch-zfs-dataset-canmount-on.txt $ make obj depend all install The change adds to the complex condition as I did not want to refactor it too much given the unclear "contrib" status of the code. Also attached is a test script to see the functionality before and after. I did some research and neither OpenIndiana/Illumos nor ZfsOnLinux have addressed this issue. Not sure the proper way to share or report this "upstream" currently. Regards, Bryan Drewery --------------040108060500020307070404 Content-Type: text/plain; charset=windows-1252; name="patch-zfs-dataset-canmount-on.txt" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="patch-zfs-dataset-canmount-on.txt" --- cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c.orig 2012-06-12 00:10:11.000000000 -0500 +++ cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c 2012-06-12 00:17:34.000000000 -0500 @@ -1467,11 +1467,12 @@ /* * If the dataset's canmount property is being set to noauto, + * or to on and already mounted, * then we want to prevent unmounting & remounting it. */ do_prefix = !((prop == ZFS_PROP_CANMOUNT) && (zprop_string_to_index(prop, propval, &idx, - ZFS_TYPE_DATASET) == 0) && (idx == ZFS_CANMOUNT_NOAUTO)); + ZFS_TYPE_DATASET) == 0) && (idx == ZFS_CANMOUNT_NOAUTO || (idx == ZFS_CANMOUNT_ON && zfs_is_mounted(zhp, NULL)))); if (do_prefix && (ret = changelist_prefix(cl)) != 0) goto error; --------------040108060500020307070404 Content-Type: text/plain; charset=windows-1252; name="test-zsh.sh" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="test-zsh.sh" #! /bin/sh set -e cleanup() { test -z "${PASS}" && echo "FAILED" cd / zpool destroy zpool mdconfig -d -u 0 mdconfig -d -u 1 } run() { echo "$@" "$@" return $? } trap cleanup SIGINT SIGTERM SIGKILL EXIT rm -rf /tmp/test mdconfig -a -t swap -s 128M -u 0 mdconfig -a -t swap -s 128M -u 1 zpool create zpool mirror md0 md1 zfs create -o mountpoint=/tmp/test -o canmount=on zpool/test cd /tmp/test # This fails even though the property is not changing and dataset is already mounted run zfs set canmount=on zpool/test # Currently works run zfs set canmount=noauto zpool/test # Expect this to try to unmount and fail, may warrant more discussion #run zfs set canmount=off zpool/test # This fails even though the property is not changing and dataset is already mounted run zfs set canmount=on zpool/test echo "PASS" PASS=1 --------------040108060500020307070404-- From owner-freebsd-fs@FreeBSD.ORG Tue Jun 12 13:54:28 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 01C69106564A for ; Tue, 12 Jun 2012 13:54:28 +0000 (UTC) (envelope-from marc@mpeters.org) Received: from mail.mpeters.org (mail.mpeters.org [78.46.104.142]) by mx1.freebsd.org (Postfix) with ESMTP id AE8C58FC27 for ; Tue, 12 Jun 2012 13:54:27 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by mail.mpeters.org (Postfix) with ESMTP id EDA5513203D for ; Tue, 12 Jun 2012 15:47:06 +0200 (CEST) X-Virus-Scanned: amavisd-new at mpeters.org Received: from mail.mpeters.org ([127.0.0.1]) by localhost (mail.mpeters.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id eKB_jApvgqDa for ; Tue, 12 Jun 2012 15:47:05 +0200 (CEST) Received: from [192.168.0.204] (unknown [62.159.86.18]) by mail.mpeters.org (Postfix) with ESMTPSA id 27CCC132038 for ; Tue, 12 Jun 2012 15:47:05 +0200 (CEST) Message-ID: <4FD74858.6070705@mpeters.org> Date: Tue, 12 Jun 2012 15:47:04 +0200 From: Marc Peters User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:10.0.4) Gecko/20120513 Thunderbird/10.0.4 MIME-Version: 1.0 To: freebsd-fs@freebsd.org X-Enigmail-Version: 1.3.5 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Subject: ZFS deletes ACLs when root edits a file X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 12 Jun 2012 13:54:28 -0000 -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi list, i observed a strange behaviour when using ACLs on a ZFS filesystem. When a file has ACLs set and is edited by a user, the ACLs get lost when the file is edited and saved. How to repeat: > mount /dev/aacd0s1a on / (ufs, local) devfs on /dev (devfs, local, multilabel) /dev/aacd0s1d on /var (ufs, local, soft-updates) appdata on /appdata (zfs, local, nfsv4acls) /dev/md0 on /appdata/www/cache (ufs, local, soft-updates) > ls -al total 3 drwxr-xr-x 2 mpeters wheel 2 Jun 12 15:31 . drwxr-xr-x 5 root wheel 5 Jun 12 15:29 .. > touch test.file ls -al total 4 drwxr-xr-x 2 mpeters wheel 3 Jun 12 15:32 . drwxr-xr-x 5 root wheel 5 Jun 12 15:29 .. - -rw-r--r-- 1 mpeters wheel 0 Jun 12 15:32 test.file > getfacl test.file # file: test.file # owner: mpeters # group: wheel owner@:rw-p--aARWcCos:------:allow group@:r-----a-R-c--s:------:allow everyone@:r-----a-R-c--s:------:allow > setfacl -m user:nobody:rwx::allow test.file ls -al total 4 drwxr-xr-x 2 mpeters wheel 3 Jun 12 15:32 . drwxr-xr-x 5 root wheel 5 Jun 12 15:29 .. - -rw-r--r--+ 1 mpeters wheel 0 Jun 12 15:32 test.file > getfacl test.file # file: test.file # owner: mpeters # group: wheel user:nobody:rwx-----------:------:allow owner@:rw-p--aARWcCos:------:allow group@:r-----a-R-c--s:------:allow everyone@:r-----a-R-c--s:------:allow > vim test.file (do some editing here) "test.file" 2 lines, 12 characters written > ls -al total 4 drwxr-xr-x 2 mpeters wheel 3 Jun 12 15:35 . drwxr-xr-x 5 root wheel 5 Jun 12 15:29 .. - -rw-r--r-- 1 mpeters wheel 12 Jun 12 15:35 test.file > getfacl test.file # file: test.file # owner: mpeters # group: wheel owner@:rw-p--aARWcCos:------:allow group@:r-----a-R-c--s:------:allow everyone@:r-----a-R-c--s:------:allow As you can see, the ACL for user nobody is gone. Is this behaviour intended? Regards, marc -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.17 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAk/XSFgACgkQCnBgS+kUGEvTGwCfSmSE31TK4cHAcs3eXdiHLwDR ofIAoJqO2A+LyIhA17YsNnWz2Z3lTogo =UcvA -----END PGP SIGNATURE----- From owner-freebsd-fs@FreeBSD.ORG Tue Jun 12 14:45:46 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 5686E106564A for ; Tue, 12 Jun 2012 14:45:46 +0000 (UTC) (envelope-from freebsd-listen@fabiankeil.de) Received: from smtprelay03.ispgateway.de (smtprelay03.ispgateway.de [80.67.31.37]) by mx1.freebsd.org (Postfix) with ESMTP id DC4918FC14 for ; Tue, 12 Jun 2012 14:45:45 +0000 (UTC) Received: from [78.35.186.150] (helo=fabiankeil.de) by smtprelay03.ispgateway.de with esmtpsa (TLSv1:AES128-SHA:128) (Exim 4.68) (envelope-from ) id 1SeSIM-0006Nr-FW; Tue, 12 Jun 2012 16:42:10 +0200 Date: Tue, 12 Jun 2012 16:42:06 +0200 From: Fabian Keil To: Marc Peters Message-ID: <20120612164206.6a573136@fabiankeil.de> In-Reply-To: <4FD74858.6070705@mpeters.org> References: <4FD74858.6070705@mpeters.org> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=PGP-SHA1; boundary="Sig_/2MyX2GgjDq8WTdUpEUgk2Im"; protocol="application/pgp-signature" X-Df-Sender: Nzc1MDY3 Cc: freebsd-fs@freebsd.org Subject: Re: ZFS deletes ACLs when root edits a file X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 12 Jun 2012 14:45:46 -0000 --Sig_/2MyX2GgjDq8WTdUpEUgk2Im Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: quoted-printable Marc Peters wrote: > i observed a strange behaviour when using ACLs on a ZFS filesystem. > When a file has ACLs set and is edited by a user, the ACLs get lost > when the file is edited and saved. >=20 > How to repeat: >=20 > > mount > /dev/aacd0s1a on / (ufs, local) > devfs on /dev (devfs, local, multilabel) > /dev/aacd0s1d on /var (ufs, local, soft-updates) > appdata on /appdata (zfs, local, nfsv4acls) > /dev/md0 on /appdata/www/cache (ufs, local, soft-updates) >=20 > > ls -al > total 3 > drwxr-xr-x 2 mpeters wheel 2 Jun 12 15:31 . > drwxr-xr-x 5 root wheel 5 Jun 12 15:29 .. > > touch test.file ls -al > total 4 > drwxr-xr-x 2 mpeters wheel 3 Jun 12 15:32 . > drwxr-xr-x 5 root wheel 5 Jun 12 15:29 .. > - -rw-r--r-- 1 mpeters wheel 0 Jun 12 15:32 test.file > > getfacl test.file > # file: test.file > # owner: mpeters > # group: wheel > owner@:rw-p--aARWcCos:------:allow > group@:r-----a-R-c--s:------:allow > everyone@:r-----a-R-c--s:------:allow > > setfacl -m user:nobody:rwx::allow test.file ls -al > total 4 > drwxr-xr-x 2 mpeters wheel 3 Jun 12 15:32 . > drwxr-xr-x 5 root wheel 5 Jun 12 15:29 .. > - -rw-r--r--+ 1 mpeters wheel 0 Jun 12 15:32 test.file > > getfacl test.file > # file: test.file > # owner: mpeters > # group: wheel > user:nobody:rwx-----------:------:allow > owner@:rw-p--aARWcCos:------:allow > group@:r-----a-R-c--s:------:allow > everyone@:r-----a-R-c--s:------:allow > > vim test.file > (do some editing here) > "test.file" 2 lines, 12 characters written > > ls -al > total 4 > drwxr-xr-x 2 mpeters wheel 3 Jun 12 15:35 . > drwxr-xr-x 5 root wheel 5 Jun 12 15:29 .. > - -rw-r--r-- 1 mpeters wheel 12 Jun 12 15:35 test.file > > getfacl test.file > # file: test.file > # owner: mpeters > # group: wheel > owner@:rw-p--aARWcCos:------:allow > group@:r-----a-R-c--s:------:allow > everyone@:r-----a-R-c--s:------:allow >=20 > As you can see, the ACL for user nobody is gone. >=20 > Is this behaviour intended? It is expected if vim replaced the original test.file with a modified file with the same name, instead of actually editing the original file directly. To confirm that this is happening you could truss vim or run "ls -i test.file" before and after using vim (this is probably less reliable, though). The ACLs shouldn't get lost if you really modify the original, for example with: echo blafasel >> test.file Fabian --Sig_/2MyX2GgjDq8WTdUpEUgk2Im Content-Type: application/pgp-signature; name=signature.asc Content-Disposition: attachment; filename=signature.asc -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (FreeBSD) iEYEARECAAYFAk/XVUEACgkQBYqIVf93VJ1VHgCgyQv+qeZYwWMb0EpoSGO6aa4v 2gQAn0zygoZMZnTxQjjUBdJJhbi0JS8O =HouI -----END PGP SIGNATURE----- --Sig_/2MyX2GgjDq8WTdUpEUgk2Im-- From owner-freebsd-fs@FreeBSD.ORG Tue Jun 12 19:15:12 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 24A4610656D5 for ; Tue, 12 Jun 2012 19:15:12 +0000 (UTC) (envelope-from lists@hurricane-ridge.com) Received: from mail-vb0-f54.google.com (mail-vb0-f54.google.com [209.85.212.54]) by mx1.freebsd.org (Postfix) with ESMTP id CD52A8FC1B for ; Tue, 12 Jun 2012 19:15:11 +0000 (UTC) Received: by vbmv11 with SMTP id v11so3827234vbm.13 for ; Tue, 12 Jun 2012 12:15:11 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=mime-version:x-originating-ip:in-reply-to:references:date :message-id:subject:from:to:cc:content-type :content-transfer-encoding:x-gm-message-state; bh=5aE0ae4zON0pt9YfHjUf38xjmzCpd4CsdnvtC7YiL0M=; b=JWm35AbU6d2E9ey8l4NhcnbPKmGvVptx8LGiatwftGJTPzhVA8+iIQ6TuetyzcITcg Fh2xzdFPjeOke5KNN7I3nsmosg4WZcbmQCyAiAR4uMqnLkJ9ueQOpM125YO6upFEIxnu r6FH3mZ9dvGNa8Bb0JHjhCuhvQ1a2SGihrtAQXNjCoq0lgyfwWxT7V1bX7r4yRSVXmgY riIMZBu1nOT2TZORKRRiPC+vYQSEAwlXrMgBTgd56F459Lj9DIFIvZJ1XqGFo1BRnICt J5gbYfVhhpSL2AJFAOK/ksLQUSFMHbs8ry74uYruJ6g9pEiaEVqiaYrKO/dPG1PU/MgE 3gTg== MIME-Version: 1.0 Received: by 10.52.33.140 with SMTP id r12mr934581vdi.91.1339528510729; Tue, 12 Jun 2012 12:15:10 -0700 (PDT) Received: by 10.52.88.162 with HTTP; Tue, 12 Jun 2012 12:15:10 -0700 (PDT) X-Originating-IP: [209.124.184.194] In-Reply-To: <20120612164206.6a573136@fabiankeil.de> References: <4FD74858.6070705@mpeters.org> <20120612164206.6a573136@fabiankeil.de> Date: Tue, 12 Jun 2012 12:15:10 -0700 Message-ID: From: Andrew Leonard To: Marc Peters Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable X-Gm-Message-State: ALoCoQlFqm649mlfWTu3wYKcam4Isy+cgB4Sks9Q2KACJhwPcuSsYdIc8jwWH18bERHLBt2CO8tL Cc: freebsd-fs@freebsd.org Subject: Re: ZFS deletes ACLs when root edits a file X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 12 Jun 2012 19:15:12 -0000 On Tue, Jun 12, 2012 at 7:42 AM, Fabian Keil wrote: > Marc Peters wrote: > >> i observed a strange behaviour when using ACLs on a ZFS filesystem. >> When a file has ACLs set and is edited by a user, the ACLs get lost >> when the file is edited and saved. >> >> How to repeat: >> >> > mount >> /dev/aacd0s1a on / (ufs, local) >> devfs on /dev (devfs, local, multilabel) >> /dev/aacd0s1d on /var (ufs, local, soft-updates) >> appdata on /appdata (zfs, local, nfsv4acls) >> /dev/md0 on /appdata/www/cache (ufs, local, soft-updates) >> >> > ls -al >> total 3 >> drwxr-xr-x =A02 mpeters =A0wheel =A02 Jun 12 15:31 . >> drwxr-xr-x =A05 root =A0 =A0 wheel =A05 Jun 12 15:29 .. >> > touch test.file ls -al >> total 4 >> drwxr-xr-x =A02 mpeters =A0wheel =A03 Jun 12 15:32 . >> drwxr-xr-x =A05 root =A0 =A0 wheel =A05 Jun 12 15:29 .. >> - -rw-r--r-- =A01 mpeters =A0wheel =A00 Jun 12 15:32 test.file >> > getfacl test.file >> # file: test.file >> # owner: mpeters >> # group: wheel >> =A0 =A0 =A0 =A0 =A0 =A0 owner@:rw-p--aARWcCos:------:allow >> =A0 =A0 =A0 =A0 =A0 =A0 group@:r-----a-R-c--s:------:allow >> =A0 =A0 =A0 =A0 =A0everyone@:r-----a-R-c--s:------:allow >> > setfacl -m user:nobody:rwx::allow test.file ls -al >> total 4 >> drwxr-xr-x =A02 mpeters =A0wheel =A03 Jun 12 15:32 . >> drwxr-xr-x =A05 root =A0 =A0 wheel =A05 Jun 12 15:29 .. >> - -rw-r--r--+ 1 mpeters =A0wheel =A00 Jun 12 15:32 test.file >> > getfacl test.file >> # file: test.file >> # owner: mpeters >> # group: wheel >> =A0 =A0 =A0 =A0user:nobody:rwx-----------:------:allow >> =A0 =A0 =A0 =A0 =A0 =A0 owner@:rw-p--aARWcCos:------:allow >> =A0 =A0 =A0 =A0 =A0 =A0 group@:r-----a-R-c--s:------:allow >> =A0 =A0 =A0 =A0 =A0everyone@:r-----a-R-c--s:------:allow >> > vim test.file >> (do some editing here) >> "test.file" 2 lines, 12 characters written >> > ls -al >> total 4 >> drwxr-xr-x =A02 mpeters =A0wheel =A0 3 Jun 12 15:35 . >> drwxr-xr-x =A05 root =A0 =A0 wheel =A0 5 Jun 12 15:29 .. >> - -rw-r--r-- =A01 mpeters =A0wheel =A012 Jun 12 15:35 test.file >> > getfacl test.file >> # file: test.file >> # owner: mpeters >> # group: wheel >> =A0 =A0 =A0 =A0 =A0 =A0 owner@:rw-p--aARWcCos:------:allow >> =A0 =A0 =A0 =A0 =A0 =A0 group@:r-----a-R-c--s:------:allow >> =A0 =A0 =A0 =A0 =A0everyone@:r-----a-R-c--s:------:allow >> >> As you can see, the ACL for user nobody is gone. >> >> Is this behaviour intended? > > It is expected if vim replaced the original test.file > with a modified file with the same name, instead of > actually editing the original file directly. > > To confirm that this is happening you could truss > vim or run "ls -i test.file" before and after using > vim (this is probably less reliable, though). > > The ACLs shouldn't get lost if you really modify the > original, for example with: > > echo blafasel >> test.file Also, take a look at what you have the aclmode property set to on the ZFS file system. If you have it set to "discard" and if vim makes a chmod(2) call on the original file, then the ACL entries that do not represent the mode of the file will be discarded. -Andy > Fabian From owner-freebsd-fs@FreeBSD.ORG Tue Jun 12 19:20:08 2012 Return-Path: Delivered-To: freebsd-fs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 28DB91065674 for ; Tue, 12 Jun 2012 19:20:08 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id EF5A78FC1F for ; Tue, 12 Jun 2012 19:20:07 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.5/8.14.5) with ESMTP id q5CJK7iB009289 for ; Tue, 12 Jun 2012 19:20:07 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.5/8.14.5/Submit) id q5CJK7qj009288; Tue, 12 Jun 2012 19:20:07 GMT (envelope-from gnats) Date: Tue, 12 Jun 2012 19:20:07 GMT Message-Id: <201206121920.q5CJK7qj009288@freefall.freebsd.org> To: freebsd-fs@FreeBSD.org From: =?UTF-8?B?VsOhY2xhdiBaZW1hbg==?= Cc: Subject: Re: kern/161424: [nullfs] __getcwd() calls fail when used on nullfs mount X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: =?UTF-8?B?VsOhY2xhdiBaZW1hbg==?= List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 12 Jun 2012 19:20:08 -0000 The following reply was made to PR kern/161424; it has been noted by GNATS. From: =?UTF-8?B?VsOhY2xhdiBaZW1hbg==?= To: Mateusz Guzik Cc: bug-followup@FreeBSD.org Subject: Re: kern/161424: [nullfs] __getcwd() calls fail when used on nullfs mount Date: Tue, 12 Jun 2012 21:19:54 +0200 On 06/11/2012 08:37 PM, Mateusz Guzik wrote: > Hi, > > are you able to reproduce this problem on FreeBSD 9.0? I cannot reproduce it right now but I do not have clean 9.0 release available. -- VZ From owner-freebsd-fs@FreeBSD.ORG Tue Jun 12 19:30:15 2012 Return-Path: Delivered-To: freebsd-fs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 2E35B10656A6 for ; Tue, 12 Jun 2012 19:30:15 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id F32C98FC0C for ; Tue, 12 Jun 2012 19:30:14 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.5/8.14.5) with ESMTP id q5CJUEUp017898 for ; Tue, 12 Jun 2012 19:30:14 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.5/8.14.5/Submit) id q5CJUEI5017897; Tue, 12 Jun 2012 19:30:14 GMT (envelope-from gnats) Date: Tue, 12 Jun 2012 19:30:14 GMT Message-Id: <201206121930.q5CJUEI5017897@freefall.freebsd.org> To: freebsd-fs@FreeBSD.org From: Michael Donaghy Cc: Subject: Re: kern/164370: [zfs] zfs destroy for snapshot fails on i386 and sparc64 X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Michael Donaghy List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 12 Jun 2012 19:30:15 -0000 The following reply was made to PR kern/164370; it has been noted by GNATS. From: Michael Donaghy To: bug-followup@FreeBSD.org, KOT@MATPOCKuH.Ru Cc: Subject: Re: kern/164370: [zfs] zfs destroy for snapshot fails on i386 and sparc64 Date: Tue, 12 Jun 2012 20:22:13 +0100 I have this problem on my amd64 system, so it's not as simple as i386/sparc vs amd64. From owner-freebsd-fs@FreeBSD.ORG Wed Jun 13 10:09:07 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 1861E1065672 for ; Wed, 13 Jun 2012 10:09:07 +0000 (UTC) (envelope-from i.junus@gmail.com) Received: from mail-wi0-f172.google.com (mail-wi0-f172.google.com [209.85.212.172]) by mx1.freebsd.org (Postfix) with ESMTP id 990D58FC14 for ; Wed, 13 Jun 2012 10:09:06 +0000 (UTC) Received: by wibhj8 with SMTP id hj8so4122402wib.13 for ; Wed, 13 Jun 2012 03:09:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:date:message-id:subject:from:to:content-type; bh=SVe21JHbApgX1B8iQcJBWZ6JZgsvt+OeX3nZgx6FYog=; b=0awKDup+nb9yK5OnCIs/7mrUbAfbnFx3sksQGuJLVEYA8KoFliElLYsHKaMXe1Uq/5 0uw55Ut58DD774r9TUhUecJTlMHD+W0e+fzN3b4UUMY1McyWk2aVwXh0QQcR7lyf9e7g UeU72ke0hoGh4buQVskyJupUXgFNO6zdvHLc0LoAk4//w8CokGT+xdSCxIdqyQDF0ndo ZttQaYV/t0q912A8858fHS88Q7DSqCTTyCjadbpgZqunWDS6AzRTkZ6pVjYf39YEmjaL soShVLqL7blbsWeydOvvRzj5jVpqZ5guaYxos4KuE4rndCbI2E9l0Q71LZFe494J3SjA pnlA== MIME-Version: 1.0 Received: by 10.180.98.201 with SMTP id ek9mr36824617wib.7.1339582140260; Wed, 13 Jun 2012 03:09:00 -0700 (PDT) Received: by 10.194.33.42 with HTTP; Wed, 13 Jun 2012 03:09:00 -0700 (PDT) Date: Wed, 13 Jun 2012 18:09:00 +0800 Message-ID: From: Irjohn Junus To: freebsd-fs@freebsd.org Content-Type: text/plain; charset=ISO-8859-1 X-Content-Filtered-By: Mailman/MimeDel 2.1.5 Subject: gpart add -a 4096 vs 4k X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 13 Jun 2012 10:09:07 -0000 Hello, Relatively new to FreeBSD and learning, I'm trying to partition my HDD and align it to 4k sector. I do apologize if this has been answered before, I have Googled and read gpart(8) man page to no joy. Can anyone please advice why gpart add '-a 4096' doesn't yield the same result with '-a 4k'? Many thanks and captures are below. Regards, Ronjns #gpart add -t freebsd-zfs -l hdd0 *-a 4096* da0 da0p1 added # gpart show da0 => 34 3907029101 da0 GPT (1.8T) 34 4062 - free - (2M) *4096 3907022848* 1 freebsd-zfs (1.8T) 3907026944 2191 - free - (1.1M) # gpart add -t freebsd-zfs -l hdd0 *-a 4k* da0 da0p1 added # gpart show da0 => 34 3907029101 da0 GPT (1.8T) 34 6 - free - (3.0k) *40 3907029088* 1 freebsd-zfs (1.8T) 3907029128 7 - free - (3.5k) From owner-freebsd-fs@FreeBSD.ORG Wed Jun 13 10:18:16 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 40A8D106564A for ; Wed, 13 Jun 2012 10:18:16 +0000 (UTC) (envelope-from olivier@gid0.org) Received: from mail-lb0-f182.google.com (mail-lb0-f182.google.com [209.85.217.182]) by mx1.freebsd.org (Postfix) with ESMTP id B1CFD8FC15 for ; Wed, 13 Jun 2012 10:18:15 +0000 (UTC) Received: by lbon10 with SMTP id n10so1367817lbo.13 for ; Wed, 13 Jun 2012 03:18:14 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type:content-transfer-encoding:x-gm-message-state; bh=zCBA62jd//LY1/BUdrKRlNwkLTyC3yQ2rAvxiJYE43c=; b=giz2NraZnFZPIEWkiVxwbM9bXl/Vbt9xtCjPfbGf6NGJVNFDu0S6Jxqc7SWkH/R72R gBG/iFNy5o3Y4093lGPuxJ4KKLpRFNmFE45BLh5DWy7qbUoKiqBCJPT4jO4eaiZxQoFx E74Ko/MAkkxeuMlFeQFWfcUC626uqzQact9WC0qyYJwrv42oBFpDU0xd6IVX3Jy0C9m9 4zS3BTo+g6K5IouwOaNC6T5VBaCnyqKO2SMZ9xl7qlX/ryV9PzzHWi9iVzSQnMYYsICK gxQ6LPkgW/zfjrLby6Uu9jXoo/OrZTlF52+F7lEZ+sP5XnbLm6lg8GBRld/PcXZzP7Ef 6eCw== MIME-Version: 1.0 Received: by 10.152.148.169 with SMTP id tt9mr23686015lab.49.1339582694333; Wed, 13 Jun 2012 03:18:14 -0700 (PDT) Received: by 10.112.100.68 with HTTP; Wed, 13 Jun 2012 03:18:14 -0700 (PDT) In-Reply-To: References: Date: Wed, 13 Jun 2012 12:18:14 +0200 Message-ID: From: Olivier Smedts To: Irjohn Junus Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable X-Gm-Message-State: ALoCoQldMJpN/o9fzjdIJHU6s6QMP4zbgb3CccGVBRnD52TcXHCTwtSYQZO9pQdpUIrKws8ItknS Cc: freebsd-fs@freebsd.org Subject: Re: gpart add -a 4096 vs 4k X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 13 Jun 2012 10:18:16 -0000 Hello, 2012/6/13 Irjohn Junus : > Hello, > > Relatively new to FreeBSD and learning, I'm trying to partition my HDD an= d > align it to 4k sector. > > I do apologize if this has been answered before, I have Googled and read > gpart(8) man page to no joy. Can anyone please advice why gpart add '-a > 4096' doesn't yield the same result with '-a 4k'? Many thanks and capture= s > are below. > > Regards, > Ronjns > > > > #gpart add -t freebsd-zfs -l hdd0 *-a 4096* da0 > da0p1 added > # gpart show da0 > =3D> =A0 =A0 =A0 =A034 =A03907029101 =A0da0 =A0GPT =A0(1.8T) > =A0 =A0 =A0 =A0 =A034 =A0 =A0 =A0 =A04062 =A0 =A0 =A0 - free - =A0(2M) > =A0 =A0 =A0 =A0*4096 =A03907022848* =A0 =A01 =A0freebsd-zfs =A0(1.8T) > =A03907026944 =A0 =A0 =A0 =A02191 =A0 =A0 =A0 - free - =A0(1.1M) > > > > # gpart add -t freebsd-zfs -l hdd0 *-a 4k* da0 > da0p1 added > # gpart show da0 > =3D> =A0 =A0 =A0 =A034 =A03907029101 =A0da0 =A0GPT =A0(1.8T) > =A0 =A0 =A0 =A0 =A034 =A0 =A0 =A0 =A0 =A0 6 =A0 =A0 =A0 - free - =A0(3.0k= ) > =A0 =A0 =A0 =A0 =A0*40 =A03907029088* =A0 =A01 =A0freebsd-zfs =A0(1.8T) > =A03907029128 =A0 =A0 =A0 =A0 =A0 7 =A0 =A0 =A0 - free - =A0(3.5k) We're talking of sectors here, se "4096" does not mean 4 KB but 4096*512=3D= 2MB. I think you should use "-a 8", because 4k sectors =3D 8*512B sectors. --=20 Olivier Smedts=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=A0 _ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 ASCII ribbon campaign ( ) e-mail: olivier@gid0.org=A0 =A0 =A0 =A0 - against HTML email & vCards=A0 X www: http://www.gid0.org=A0 =A0 - against proprietary attachments / \ =A0 "Il y a seulement 10 sortes de gens dans le monde : =A0 ceux qui comprennent le binaire, =A0 et ceux qui ne le comprennent pas." From owner-freebsd-fs@FreeBSD.ORG Wed Jun 13 07:00:28 2012 Return-Path: Delivered-To: freebsd-fs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 7DE57106564A for ; Wed, 13 Jun 2012 07:00:28 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [69.147.83.40]) by mx1.freebsd.org (Postfix) with ESMTP id 62C688FC14 for ; Wed, 13 Jun 2012 07:00:28 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.5/8.14.5) with ESMTP id q5D70SJ9083554 for ; Wed, 13 Jun 2012 07:00:28 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.5/8.14.5/Submit) id q5D70R4j083553; Wed, 13 Jun 2012 07:00:27 GMT (envelope-from gnats) Date: Wed, 13 Jun 2012 07:00:27 GMT Message-Id: <201206130700.q5D70R4j083553@freefall.freebsd.org> To: freebsd-fs@FreeBSD.org From: vermaden X-Mailman-Approved-At: Wed, 13 Jun 2012 11:00:59 +0000 Cc: Subject: Re: kern/167905: [zfs] zfs set canmount=on UNMOUNTS dataset X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: vermaden List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 13 Jun 2012 07:00:28 -0000 The following reply was made to PR kern/167905; it has been noted by GNATS. From: vermaden To: Bryan Drewery Cc: bug-followup@FreeBSD.org, Pawel Jakub Dawidek , mm@freebsd.org Subject: Re: kern/167905: [zfs] zfs set canmount=on UNMOUNTS dataset Date: Wed, 13 Jun 2012 08:37:24 +0200 --=-eOAg1opG/d7eXMURa76A Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi, at last I had some time to check Your work, but the patch did not applied t= o 9-STABLE @ r236934: / # cd /usr/src/cddl=20 /usr/src/cddl # patch -p1 < /root/patch-zfs-dataset-canmount-on Hmm... Looks like a unified diff to me... The text leading up to this was: -------------------------- |--- cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c.orig 201= 2-06-12 00:10:11.000000000 -0500 |+++ cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c 201= 2-06-12 00:17:34.000000000 -0500 -------------------------- Patching file contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c using = Plan A... Hunk #1 failed at 1467. 1 out of 1 hunks failed--saving rejects to contrib/opensolaris/lib/libzfs/c= ommon/libzfs_dataset.c.rej done Regards, vermaden "Bryan Drewery" pisze: > Attached is a patch to fix setting 'zfs set canmount=3Don' to not cause a > remount if the dataset is *already mounted*. This fixes the issue > reported here, as well as here > http://lists.freebsd.org/pipermail/freebsd-fs/2012-May/014241.html >=20 > $ cd /usr/src/cddl > $ patch -p1 < patch-zfs-dataset-canmount-on.txt > $ make obj depend all install >=20 > The change adds to the complex condition as I did not want to refactor > it too much given the unclear "contrib" status of the code. >=20 > Also attached is a test script to see the functionality before and after. >=20 > I did some research and neither OpenIndiana/Illumos nor ZfsOnLinux have > addressed this issue. Not sure the proper way to share or report this > "upstream" currently. >=20 > Regards, > Bryan Drewery >=20 --=20 ... --=-eOAg1opG/d7eXMURa76A Content-Type: text/plain; name="libzfs_dataset.c.rej" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="libzfs_dataset.c.rej" *************** *** 1467,1477 **** =20 /* * If the dataset's canmount property is being set to noauto, * then we want to prevent unmounting & remounting it. */ do_prefix =3D !((prop =3D=3D ZFS_PROP_CANMOUNT) && (zprop_string_to_index(prop, propval, &idx, - ZFS_TYPE_DATASET) =3D=3D 0) && (idx =3D=3D ZFS_CANMOUNT_NOAUTO)); =20 if (do_prefix && (ret =3D changelist_prefix(cl)) !=3D 0) goto error; --- 1467,1478 ---- =20 /* * If the dataset's canmount property is being set to noauto, + * or to on and already mounted, * then we want to prevent unmounting & remounting it. */ do_prefix =3D !((prop =3D=3D ZFS_PROP_CANMOUNT) && (zprop_string_to_index(prop, propval, &idx, + ZFS_TYPE_DATASET) =3D=3D 0) && (idx =3D=3D ZFS_CANMOUNT_NOAUTO || (i= dx =3D=3D ZFS_CANMOUNT_ON && zfs_is_mounted(zhp, NULL)))); =20 if (do_prefix && (ret =3D changelist_prefix(cl)) !=3D 0) goto error; --=-eOAg1opG/d7eXMURa76A Content-Type: text/plain; name="libzfs_dataset.c.orig" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="libzfs_dataset.c.orig" /* * 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) 2005, 2010, Oracle and/or its affiliates. All rights reser= ved. * Copyright 2010 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2011 by Delphix. All rights reserved. * Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved. * Copyright (c) 2011-2012 Pawel Jakub Dawidek . * All rights reserved. * Copyright (c) 2012 Martin Matuska . All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "zfs_namecheck.h" #include "zfs_prop.h" #include "libzfs_impl.h" #include "zfs_deleg.h" static int userquota_propname_decode(const char *propname, boolean_t zoned, zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *rid= p); /* * Given a single type (not a mask of types), return the type in a human * readable form. */ const char * zfs_type_to_name(zfs_type_t type) { switch (type) { case ZFS_TYPE_FILESYSTEM: return (dgettext(TEXT_DOMAIN, "filesystem")); case ZFS_TYPE_SNAPSHOT: return (dgettext(TEXT_DOMAIN, "snapshot")); case ZFS_TYPE_VOLUME: return (dgettext(TEXT_DOMAIN, "volume")); } return (NULL); } /* * Given a path and mask of ZFS types, return a string describing this data= set. * This is used when we fail to open a dataset and we cannot get an exact t= ype. * We guess what the type would have been based on the path and the mask of * acceptable types. */ static const char * path_to_str(const char *path, int types) { /* * When given a single type, always report the exact type. */ if (types =3D=3D ZFS_TYPE_SNAPSHOT) return (dgettext(TEXT_DOMAIN, "snapshot")); if (types =3D=3D ZFS_TYPE_FILESYSTEM) return (dgettext(TEXT_DOMAIN, "filesystem")); if (types =3D=3D ZFS_TYPE_VOLUME) return (dgettext(TEXT_DOMAIN, "volume")); /* * The user is requesting more than one type of dataset. If this is the * case, consult the path itself. If we're looking for a snapshot, and * a '@' is found, then report it as "snapshot". Otherwise, remove the * snapshot attribute and try again. */ if (types & ZFS_TYPE_SNAPSHOT) { if (strchr(path, '@') !=3D NULL) return (dgettext(TEXT_DOMAIN, "snapshot")); return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT)); } /* * The user has requested either filesystems or volumes. * We have no way of knowing a priori what type this would be, so always * report it as "filesystem" or "volume", our two primitive types. */ if (types & ZFS_TYPE_FILESYSTEM) return (dgettext(TEXT_DOMAIN, "filesystem")); assert(types & ZFS_TYPE_VOLUME); return (dgettext(TEXT_DOMAIN, "volume")); } /* * Validate a ZFS path. This is used even before trying to open the datase= t, to * provide a more meaningful error message. We call zfs_error_aux() to * explain exactly why the name was not valid. */ int zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type, boolean_t modifying) { namecheck_err_t why; char what; (void) zfs_prop_get_table(); if (dataset_namecheck(path, &why, &what) !=3D 0) { if (hdl !=3D NULL) { switch (why) { case NAME_ERR_TOOLONG: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "name is too long")); break; case NAME_ERR_LEADING_SLASH: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "leading slash in name")); break; case NAME_ERR_EMPTY_COMPONENT: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "empty component in name")); break; case NAME_ERR_TRAILING_SLASH: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "trailing slash in name")); break; case NAME_ERR_INVALCHAR: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid character " "'%c' in name"), what); break; case NAME_ERR_MULTIPLE_AT: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "multiple '@' delimiters in name")); break; case NAME_ERR_NOLETTER: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool doesn't begin with a letter")); break; case NAME_ERR_RESERVED: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "name is reserved")); break; case NAME_ERR_DISKLIKE: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "reserved disk name")); break; } } return (0); } if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') !=3D NULL) { if (hdl !=3D NULL) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "snapshot delimiter '@' in filesystem name")); return (0); } if (type =3D=3D ZFS_TYPE_SNAPSHOT && strchr(path, '@') =3D=3D NULL) { if (hdl !=3D NULL) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "missing '@' delimiter in snapshot name")); return (0); } if (modifying && strchr(path, '%') !=3D NULL) { if (hdl !=3D NULL) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid character %c in name"), '%'); return (0); } return (-1); } int zfs_name_valid(const char *name, zfs_type_t type) { if (type =3D=3D ZFS_TYPE_POOL) return (zpool_name_valid(NULL, B_FALSE, name)); return (zfs_validate_name(NULL, name, type, B_FALSE)); } /* * This function takes the raw DSL properties, and filters out the user-def= ined * properties into a separate nvlist. */ static nvlist_t * process_user_props(zfs_handle_t *zhp, nvlist_t *props) { libzfs_handle_t *hdl =3D zhp->zfs_hdl; nvpair_t *elem; nvlist_t *propval; nvlist_t *nvl; if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) !=3D 0) { (void) no_memory(hdl); return (NULL); } elem =3D NULL; while ((elem =3D nvlist_next_nvpair(props, elem)) !=3D NULL) { if (!zfs_prop_user(nvpair_name(elem))) continue; verify(nvpair_value_nvlist(elem, &propval) =3D=3D 0); if (nvlist_add_nvlist(nvl, nvpair_name(elem), propval) !=3D 0) { nvlist_free(nvl); (void) no_memory(hdl); return (NULL); } } return (nvl); } static zpool_handle_t * zpool_add_handle(zfs_handle_t *zhp, const char *pool_name) { libzfs_handle_t *hdl =3D zhp->zfs_hdl; zpool_handle_t *zph; if ((zph =3D zpool_open_canfail(hdl, pool_name)) !=3D NULL) { if (hdl->libzfs_pool_handles !=3D NULL) zph->zpool_next =3D hdl->libzfs_pool_handles; hdl->libzfs_pool_handles =3D zph; } return (zph); } static zpool_handle_t * zpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len) { libzfs_handle_t *hdl =3D zhp->zfs_hdl; zpool_handle_t *zph =3D hdl->libzfs_pool_handles; while ((zph !=3D NULL) && (strncmp(pool_name, zpool_get_name(zph), len) !=3D 0)) zph =3D zph->zpool_next; return (zph); } /* * Returns a handle to the pool that contains the provided dataset. * If a handle to that pool already exists then that handle is returned. * Otherwise, a new handle is created and added to the list of handles. */ static zpool_handle_t * zpool_handle(zfs_handle_t *zhp) { char *pool_name; int len; zpool_handle_t *zph; len =3D strcspn(zhp->zfs_name, "/@") + 1; pool_name =3D zfs_alloc(zhp->zfs_hdl, len); (void) strlcpy(pool_name, zhp->zfs_name, len); zph =3D zpool_find_handle(zhp, pool_name, len); if (zph =3D=3D NULL) zph =3D zpool_add_handle(zhp, pool_name); free(pool_name); return (zph); } void zpool_free_handles(libzfs_handle_t *hdl) { zpool_handle_t *next, *zph =3D hdl->libzfs_pool_handles; while (zph !=3D NULL) { next =3D zph->zpool_next; zpool_close(zph); zph =3D next; } hdl->libzfs_pool_handles =3D NULL; } /* * Utility function to gather stats (objset and zpl) for the given object. */ static int get_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc) { libzfs_handle_t *hdl =3D zhp->zfs_hdl; (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name)); while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) !=3D 0) { if (errno =3D=3D ENOMEM) { if (zcmd_expand_dst_nvlist(hdl, zc) !=3D 0) { return (-1); } } else { return (-1); } } return (0); } /* * Utility function to get the received properties of the given object. */ static int get_recvd_props_ioctl(zfs_handle_t *zhp) { libzfs_handle_t *hdl =3D zhp->zfs_hdl; nvlist_t *recvdprops; zfs_cmd_t zc =3D { 0 }; int err; if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) !=3D 0) return (-1); (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_RECVD_PROPS, &zc) !=3D 0) { if (errno =3D=3D ENOMEM) { if (zcmd_expand_dst_nvlist(hdl, &zc) !=3D 0) { return (-1); } } else { zcmd_free_nvlists(&zc); return (-1); } } err =3D zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &recvdprops); zcmd_free_nvlists(&zc); if (err !=3D 0) return (-1); nvlist_free(zhp->zfs_recvd_props); zhp->zfs_recvd_props =3D recvdprops; return (0); } static int put_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc) { nvlist_t *allprops, *userprops; zhp->zfs_dmustats =3D zc->zc_objset_stats; /* structure assignment */ if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) !=3D 0) { return (-1); } /* * XXX Why do we store the user props separately, in addition to * storing them in zfs_props? */ if ((userprops =3D process_user_props(zhp, allprops)) =3D=3D NULL) { nvlist_free(allprops); return (-1); } nvlist_free(zhp->zfs_props); nvlist_free(zhp->zfs_user_props); zhp->zfs_props =3D allprops; zhp->zfs_user_props =3D userprops; return (0); } static int get_stats(zfs_handle_t *zhp) { int rc =3D 0; zfs_cmd_t zc =3D { 0 }; if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) !=3D 0) return (-1); if (get_stats_ioctl(zhp, &zc) !=3D 0) rc =3D -1; else if (put_stats_zhdl(zhp, &zc) !=3D 0) rc =3D -1; zcmd_free_nvlists(&zc); return (rc); } /* * Refresh the properties currently stored in the handle. */ void zfs_refresh_properties(zfs_handle_t *zhp) { (void) get_stats(zhp); } /* * Makes a handle from the given dataset name. Used by zfs_open() and * zfs_iter_* to create child handles on the fly. */ static int make_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc) { if (put_stats_zhdl(zhp, zc) !=3D 0) return (-1); /* * We've managed to open the dataset and gather statistics. Determine * the high-level type. */ if (zhp->zfs_dmustats.dds_type =3D=3D DMU_OST_ZVOL) zhp->zfs_head_type =3D ZFS_TYPE_VOLUME; else if (zhp->zfs_dmustats.dds_type =3D=3D DMU_OST_ZFS) zhp->zfs_head_type =3D ZFS_TYPE_FILESYSTEM; else abort(); if (zhp->zfs_dmustats.dds_is_snapshot) zhp->zfs_type =3D ZFS_TYPE_SNAPSHOT; else if (zhp->zfs_dmustats.dds_type =3D=3D DMU_OST_ZVOL) zhp->zfs_type =3D ZFS_TYPE_VOLUME; else if (zhp->zfs_dmustats.dds_type =3D=3D DMU_OST_ZFS) zhp->zfs_type =3D ZFS_TYPE_FILESYSTEM; else abort(); /* we should never see any other types */ if ((zhp->zpool_hdl =3D zpool_handle(zhp)) =3D=3D NULL) return (-1); return (0); } zfs_handle_t * make_dataset_handle(libzfs_handle_t *hdl, const char *path) { zfs_cmd_t zc =3D { 0 }; zfs_handle_t *zhp =3D calloc(sizeof (zfs_handle_t), 1); if (zhp =3D=3D NULL) return (NULL); zhp->zfs_hdl =3D hdl; (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) !=3D 0) { free(zhp); return (NULL); } if (get_stats_ioctl(zhp, &zc) =3D=3D -1) { zcmd_free_nvlists(&zc); free(zhp); return (NULL); } if (make_dataset_handle_common(zhp, &zc) =3D=3D -1) { free(zhp); zhp =3D NULL; } zcmd_free_nvlists(&zc); return (zhp); } zfs_handle_t * make_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc) { zfs_handle_t *zhp =3D calloc(sizeof (zfs_handle_t), 1); if (zhp =3D=3D NULL) return (NULL); zhp->zfs_hdl =3D hdl; (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); if (make_dataset_handle_common(zhp, zc) =3D=3D -1) { free(zhp); return (NULL); } return (zhp); } zfs_handle_t * make_dataset_simple_handle_zc(zfs_handle_t *pzhp, zfs_cmd_t *zc) { zfs_handle_t *zhp =3D calloc(sizeof (zfs_handle_t), 1); if (zhp =3D=3D NULL) return (NULL); zhp->zfs_hdl =3D pzhp->zfs_hdl; (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); zhp->zfs_head_type =3D pzhp->zfs_type; zhp->zfs_type =3D ZFS_TYPE_SNAPSHOT; zhp->zpool_hdl =3D zpool_handle(zhp); return (zhp); } zfs_handle_t * zfs_handle_dup(zfs_handle_t *zhp_orig) { zfs_handle_t *zhp =3D calloc(sizeof (zfs_handle_t), 1); if (zhp =3D=3D NULL) return (NULL); zhp->zfs_hdl =3D zhp_orig->zfs_hdl; zhp->zpool_hdl =3D zhp_orig->zpool_hdl; (void) strlcpy(zhp->zfs_name, zhp_orig->zfs_name, sizeof (zhp->zfs_name)); zhp->zfs_type =3D zhp_orig->zfs_type; zhp->zfs_head_type =3D zhp_orig->zfs_head_type; zhp->zfs_dmustats =3D zhp_orig->zfs_dmustats; if (zhp_orig->zfs_props !=3D NULL) { if (nvlist_dup(zhp_orig->zfs_props, &zhp->zfs_props, 0) !=3D 0) { (void) no_memory(zhp->zfs_hdl); zfs_close(zhp); return (NULL); } } if (zhp_orig->zfs_user_props !=3D NULL) { if (nvlist_dup(zhp_orig->zfs_user_props, &zhp->zfs_user_props, 0) !=3D 0) { (void) no_memory(zhp->zfs_hdl); zfs_close(zhp); return (NULL); } } if (zhp_orig->zfs_recvd_props !=3D NULL) { if (nvlist_dup(zhp_orig->zfs_recvd_props, &zhp->zfs_recvd_props, 0)) { (void) no_memory(zhp->zfs_hdl); zfs_close(zhp); return (NULL); } } zhp->zfs_mntcheck =3D zhp_orig->zfs_mntcheck; if (zhp_orig->zfs_mntopts !=3D NULL) { zhp->zfs_mntopts =3D zfs_strdup(zhp_orig->zfs_hdl, zhp_orig->zfs_mntopts); } zhp->zfs_props_table =3D zhp_orig->zfs_props_table; return (zhp); } /* * Opens the given snapshot, filesystem, or volume. The 'types' * argument is a mask of acceptable types. The function will print an * appropriate error message and return NULL if it can't be opened. */ zfs_handle_t * zfs_open(libzfs_handle_t *hdl, const char *path, int types) { zfs_handle_t *zhp; char errbuf[1024]; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); /* * Validate the name before we even try to open it. */ if (!zfs_validate_name(hdl, path, ZFS_TYPE_DATASET, B_FALSE)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid dataset name")); (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); return (NULL); } /* * Try to get stats for the dataset, which will tell us if it exists. */ errno =3D 0; if ((zhp =3D make_dataset_handle(hdl, path)) =3D=3D NULL) { (void) zfs_standard_error(hdl, errno, errbuf); return (NULL); } if (!(types & zhp->zfs_type)) { (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); zfs_close(zhp); return (NULL); } return (zhp); } /* * Release a ZFS handle. Nothing to do but free the associated memory. */ void zfs_close(zfs_handle_t *zhp) { if (zhp->zfs_mntopts) free(zhp->zfs_mntopts); nvlist_free(zhp->zfs_props); nvlist_free(zhp->zfs_user_props); nvlist_free(zhp->zfs_recvd_props); free(zhp); } typedef struct mnttab_node { struct mnttab mtn_mt; avl_node_t mtn_node; } mnttab_node_t; static int libzfs_mnttab_cache_compare(const void *arg1, const void *arg2) { const mnttab_node_t *mtn1 =3D arg1; const mnttab_node_t *mtn2 =3D arg2; int rv; rv =3D strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special); if (rv =3D=3D 0) return (0); return (rv > 0 ? 1 : -1); } void libzfs_mnttab_init(libzfs_handle_t *hdl) { assert(avl_numnodes(&hdl->libzfs_mnttab_cache) =3D=3D 0); avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare, sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node)); } void libzfs_mnttab_update(libzfs_handle_t *hdl) { struct mnttab entry; rewind(hdl->libzfs_mnttab); while (getmntent(hdl->libzfs_mnttab, &entry) =3D=3D 0) { mnttab_node_t *mtn; if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) !=3D 0) continue; mtn =3D zfs_alloc(hdl, sizeof (mnttab_node_t)); mtn->mtn_mt.mnt_special =3D zfs_strdup(hdl, entry.mnt_special); mtn->mtn_mt.mnt_mountp =3D zfs_strdup(hdl, entry.mnt_mountp); mtn->mtn_mt.mnt_fstype =3D zfs_strdup(hdl, entry.mnt_fstype); mtn->mtn_mt.mnt_mntopts =3D zfs_strdup(hdl, entry.mnt_mntopts); avl_add(&hdl->libzfs_mnttab_cache, mtn); } } void libzfs_mnttab_fini(libzfs_handle_t *hdl) { void *cookie =3D NULL; mnttab_node_t *mtn; while (mtn =3D avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie)) { free(mtn->mtn_mt.mnt_special); free(mtn->mtn_mt.mnt_mountp); free(mtn->mtn_mt.mnt_fstype); free(mtn->mtn_mt.mnt_mntopts); free(mtn); } avl_destroy(&hdl->libzfs_mnttab_cache); } void libzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable) { hdl->libzfs_mnttab_enable =3D enable; } int libzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname, struct mnttab *entry) { mnttab_node_t find; mnttab_node_t *mtn; if (!hdl->libzfs_mnttab_enable) { struct mnttab srch =3D { 0 }; if (avl_numnodes(&hdl->libzfs_mnttab_cache)) libzfs_mnttab_fini(hdl); rewind(hdl->libzfs_mnttab); srch.mnt_special =3D (char *)fsname; srch.mnt_fstype =3D MNTTYPE_ZFS; if (getmntany(hdl->libzfs_mnttab, entry, &srch) =3D=3D 0) return (0); else return (ENOENT); } if (avl_numnodes(&hdl->libzfs_mnttab_cache) =3D=3D 0) libzfs_mnttab_update(hdl); find.mtn_mt.mnt_special =3D (char *)fsname; mtn =3D avl_find(&hdl->libzfs_mnttab_cache, &find, NULL); if (mtn) { *entry =3D mtn->mtn_mt; return (0); } return (ENOENT); } void libzfs_mnttab_add(libzfs_handle_t *hdl, const char *special, const char *mountp, const char *mntopts) { mnttab_node_t *mtn; if (avl_numnodes(&hdl->libzfs_mnttab_cache) =3D=3D 0) return; mtn =3D zfs_alloc(hdl, sizeof (mnttab_node_t)); mtn->mtn_mt.mnt_special =3D zfs_strdup(hdl, special); mtn->mtn_mt.mnt_mountp =3D zfs_strdup(hdl, mountp); mtn->mtn_mt.mnt_fstype =3D zfs_strdup(hdl, MNTTYPE_ZFS); mtn->mtn_mt.mnt_mntopts =3D zfs_strdup(hdl, mntopts); avl_add(&hdl->libzfs_mnttab_cache, mtn); } void libzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname) { mnttab_node_t find; mnttab_node_t *ret; find.mtn_mt.mnt_special =3D (char *)fsname; if (ret =3D avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL)) { avl_remove(&hdl->libzfs_mnttab_cache, ret); free(ret->mtn_mt.mnt_special); free(ret->mtn_mt.mnt_mountp); free(ret->mtn_mt.mnt_fstype); free(ret->mtn_mt.mnt_mntopts); free(ret); } } int zfs_spa_version(zfs_handle_t *zhp, int *spa_version) { zpool_handle_t *zpool_handle =3D zhp->zpool_hdl; if (zpool_handle =3D=3D NULL) return (-1); *spa_version =3D zpool_get_prop_int(zpool_handle, ZPOOL_PROP_VERSION, NULL); return (0); } /* * The choice of reservation property depends on the SPA version. */ static int zfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop) { int spa_version; if (zfs_spa_version(zhp, &spa_version) < 0) return (-1); if (spa_version >=3D SPA_VERSION_REFRESERVATION) *resv_prop =3D ZFS_PROP_REFRESERVATION; else *resv_prop =3D ZFS_PROP_RESERVATION; return (0); } /* * Given an nvlist of properties to set, validates that they are correct, a= nd * parses any numeric properties (index, boolean, etc) if they are specifie= d as * strings. */ nvlist_t * zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, uint64_t zoned, zfs_handle_t *zhp, const char *errbuf) { nvpair_t *elem; uint64_t intval; char *strval; zfs_prop_t prop; nvlist_t *ret; int chosen_normal =3D -1; int chosen_utf =3D -1; if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) !=3D 0) { (void) no_memory(hdl); return (NULL); } /* * Make sure this property is valid and applies to this type. */ elem =3D NULL; while ((elem =3D nvlist_next_nvpair(nvl, elem)) !=3D NULL) { const char *propname =3D nvpair_name(elem); prop =3D zfs_name_to_prop(propname); if (prop =3D=3D ZPROP_INVAL && zfs_prop_user(propname)) { /* * This is a user property: make sure it's a * string, and that it's less than ZAP_MAXNAMELEN. */ if (nvpair_type(elem) !=3D DATA_TYPE_STRING) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' must be a string"), propname); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } if (strlen(nvpair_name(elem)) >=3D ZAP_MAXNAMELEN) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "property name '%s' is too long"), propname); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } (void) nvpair_value_string(elem, &strval); if (nvlist_add_string(ret, propname, strval) !=3D 0) { (void) no_memory(hdl); goto error; } continue; } /* * Currently, only user properties can be modified on * snapshots. */ if (type =3D=3D ZFS_TYPE_SNAPSHOT) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "this property can not be modified for snapshots")); (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); goto error; } if (prop =3D=3D ZPROP_INVAL && zfs_prop_userquota(propname)) { zfs_userquota_prop_t uqtype; char newpropname[128]; char domain[128]; uint64_t rid; uint64_t valary[3]; if (userquota_propname_decode(propname, zoned, &uqtype, domain, sizeof (domain), &rid) !=3D 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' has an invalid user/group name"), propname); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } if (uqtype !=3D ZFS_PROP_USERQUOTA && uqtype !=3D ZFS_PROP_GROUPQUOTA) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' is readonly"), propname); (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); goto error; } if (nvpair_type(elem) =3D=3D DATA_TYPE_STRING) { (void) nvpair_value_string(elem, &strval); if (strcmp(strval, "none") =3D=3D 0) { intval =3D 0; } else if (zfs_nicestrtonum(hdl, strval, &intval) !=3D 0) { (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } } else if (nvpair_type(elem) =3D=3D DATA_TYPE_UINT64) { (void) nvpair_value_uint64(elem, &intval); if (intval =3D=3D 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "use 'none' to disable " "userquota/groupquota")); goto error; } } else { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' must be a number"), propname); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } /* * Encode the prop name as * userquota@-domain, to make it easy * for the kernel to decode. */ (void) snprintf(newpropname, sizeof (newpropname), "%s%llx-%s", zfs_userquota_prop_prefixes[uqtype], (longlong_t)rid, domain); valary[0] =3D uqtype; valary[1] =3D rid; valary[2] =3D intval; if (nvlist_add_uint64_array(ret, newpropname, valary, 3) !=3D 0) { (void) no_memory(hdl); goto error; } continue; } else if (prop =3D=3D ZPROP_INVAL && zfs_prop_written(propname)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' is readonly"), propname); (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); goto error; } if (prop =3D=3D ZPROP_INVAL) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid property '%s'"), propname); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } if (!zfs_prop_valid_for_type(prop, type)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' does not " "apply to datasets of this type"), propname); (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); goto error; } if (zfs_prop_readonly(prop) && (!zfs_prop_setonce(prop) || zhp !=3D NULL)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' is readonly"), propname); (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); goto error; } if (zprop_parse_value(hdl, elem, prop, type, ret, &strval, &intval, errbuf) !=3D 0) goto error; /* * Perform some additional checks for specific properties. */ switch (prop) { case ZFS_PROP_VERSION: { int version; if (zhp =3D=3D NULL) break; version =3D zfs_prop_get_int(zhp, ZFS_PROP_VERSION); if (intval < version) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "Can not downgrade; already at version %u"), version); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } break; } case ZFS_PROP_RECORDSIZE: case ZFS_PROP_VOLBLOCKSIZE: /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ if (intval < SPA_MINBLOCKSIZE || intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' must be power of 2 from %u " "to %uk"), propname, (uint_t)SPA_MINBLOCKSIZE, (uint_t)SPA_MAXBLOCKSIZE >> 10); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } break; case ZFS_PROP_MLSLABEL: { #ifdef sun /* * Verify the mlslabel string and convert to * internal hex label string. */ m_label_t *new_sl; char *hex =3D NULL; /* internal label string */ /* Default value is already OK. */ if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) =3D=3D 0) break; /* Verify the label can be converted to binary form */ if (((new_sl =3D m_label_alloc(MAC_LABEL)) =3D=3D NULL) || (str_to_label(strval, &new_sl, MAC_LABEL, L_NO_CORRECTION, NULL) =3D=3D -1)) { goto badlabel; } /* Now translate to hex internal label string */ if (label_to_str(new_sl, &hex, M_INTERNAL, DEF_NAMES) !=3D 0) { if (hex) free(hex); goto badlabel; } m_label_free(new_sl); /* If string is already in internal form, we're done. */ if (strcmp(strval, hex) =3D=3D 0) { free(hex); break; } /* Replace the label string with the internal form. */ (void) nvlist_remove(ret, zfs_prop_to_name(prop), DATA_TYPE_STRING); verify(nvlist_add_string(ret, zfs_prop_to_name(prop), hex) =3D=3D 0); free(hex); break; badlabel: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid mlslabel '%s'"), strval); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); m_label_free(new_sl); /* OK if null */ #else /* !sun */ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "mlslabel is not supported on FreeBSD")); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); #endif /* !sun */ goto error; } case ZFS_PROP_MOUNTPOINT: { namecheck_err_t why; if (strcmp(strval, ZFS_MOUNTPOINT_NONE) =3D=3D 0 || strcmp(strval, ZFS_MOUNTPOINT_LEGACY) =3D=3D 0) break; if (mountpoint_namecheck(strval, &why)) { switch (why) { case NAME_ERR_LEADING_SLASH: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' must be an absolute path, " "'none', or 'legacy'"), propname); break; case NAME_ERR_TOOLONG: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "component of '%s' is too long"), propname); break; } (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } } /*FALLTHRU*/ case ZFS_PROP_SHARESMB: case ZFS_PROP_SHARENFS: /* * For the mountpoint and sharenfs or sharesmb * properties, check if it can be set in a * global/non-global zone based on * the zoned property value: * * global zone non-global zone * -------------------------------------------------- * zoned=3Don mountpoint (no) mountpoint (yes) * sharenfs (no) sharenfs (no) * sharesmb (no) sharesmb (no) * * zoned=3Doff mountpoint (yes) N/A * sharenfs (yes) * sharesmb (yes) */ if (zoned) { if (getzoneid() =3D=3D GLOBAL_ZONEID) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' cannot be set on " "dataset in a non-global zone"), propname); (void) zfs_error(hdl, EZFS_ZONED, errbuf); goto error; } else if (prop =3D=3D ZFS_PROP_SHARENFS || prop =3D=3D ZFS_PROP_SHARESMB) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' cannot be set in " "a non-global zone"), propname); (void) zfs_error(hdl, EZFS_ZONED, errbuf); goto error; } } else if (getzoneid() !=3D GLOBAL_ZONEID) { /* * If zoned property is 'off', this must be in * a global zone. If not, something is wrong. */ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' cannot be set while dataset " "'zoned' property is set"), propname); (void) zfs_error(hdl, EZFS_ZONED, errbuf); goto error; } /* * At this point, it is legitimate to set the * property. Now we want to make sure that the * property value is valid if it is sharenfs. */ if ((prop =3D=3D ZFS_PROP_SHARENFS || prop =3D=3D ZFS_PROP_SHARESMB) && strcmp(strval, "on") !=3D 0 && strcmp(strval, "off") !=3D 0) { zfs_share_proto_t proto; if (prop =3D=3D ZFS_PROP_SHARESMB) proto =3D PROTO_SMB; else proto =3D PROTO_NFS; /* * Must be an valid sharing protocol * option string so init the libshare * in order to enable the parser and * then parse the options. We use the * control API since we don't care about * the current configuration and don't * want the overhead of loading it * until we actually do something. */ if (zfs_init_libshare(hdl, SA_INIT_CONTROL_API) !=3D SA_OK) { /* * An error occurred so we can't do * anything */ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' cannot be set: problem " "in share initialization"), propname); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } if (zfs_parse_options(strval, proto) !=3D SA_OK) { /* * There was an error in parsing so * deal with it by issuing an error * message and leaving after * uninitializing the the libshare * interface. */ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' cannot be set to invalid " "options"), propname); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); zfs_uninit_libshare(hdl); goto error; } zfs_uninit_libshare(hdl); } break; case ZFS_PROP_UTF8ONLY: chosen_utf =3D (int)intval; break; case ZFS_PROP_NORMALIZE: chosen_normal =3D (int)intval; break; } /* * For changes to existing volumes, we have some additional * checks to enforce. */ if (type =3D=3D ZFS_TYPE_VOLUME && zhp !=3D NULL) { uint64_t volsize =3D zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); uint64_t blocksize =3D zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE); char buf[64]; switch (prop) { case ZFS_PROP_RESERVATION: case ZFS_PROP_REFRESERVATION: if (intval > volsize) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' is greater than current " "volume size"), propname); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } break; case ZFS_PROP_VOLSIZE: if (intval % blocksize !=3D 0) { zfs_nicenum(blocksize, buf, sizeof (buf)); zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' must be a multiple of " "volume block size (%s)"), propname, buf); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } if (intval =3D=3D 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' cannot be zero"), propname); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } break; } } } /* * If normalization was chosen, but no UTF8 choice was made, * enforce rejection of non-UTF8 names. * * If normalization was chosen, but rejecting non-UTF8 names * was explicitly not chosen, it is an error. */ if (chosen_normal > 0 && chosen_utf < 0) { if (nvlist_add_uint64(ret, zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) !=3D 0) { (void) no_memory(hdl); goto error; } } else if (chosen_normal > 0 && chosen_utf =3D=3D 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' must be set 'on' if normalization chosen"), zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } return (ret); error: nvlist_free(ret); return (NULL); } int zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl) { uint64_t old_volsize; uint64_t new_volsize; uint64_t old_reservation; uint64_t new_reservation; zfs_prop_t resv_prop; /* * If this is an existing volume, and someone is setting the volsize, * make sure that it matches the reservation, or add it if necessary. */ old_volsize =3D zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); if (zfs_which_resv_prop(zhp, &resv_prop) < 0) return (-1); old_reservation =3D zfs_prop_get_int(zhp, resv_prop); if ((zvol_volsize_to_reservation(old_volsize, zhp->zfs_props) !=3D old_reservation) || nvlist_lookup_uint64(nvl, zfs_prop_to_name(resv_prop), &new_reservation) !=3D ENOENT) { return (0); } if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE), &new_volsize) !=3D 0) return (-1); new_reservation =3D zvol_volsize_to_reservation(new_volsize, zhp->zfs_props); if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop), new_reservation) !=3D 0) { (void) no_memory(zhp->zfs_hdl); return (-1); } return (1); } void zfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err, char *errbuf) { switch (err) { case ENOSPC: /* * For quotas and reservations, ENOSPC indicates * something different; setting a quota or reservation * doesn't use any disk space. */ switch (prop) { case ZFS_PROP_QUOTA: case ZFS_PROP_REFQUOTA: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "size is less than current used or " "reserved space")); (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); break; case ZFS_PROP_RESERVATION: case ZFS_PROP_REFRESERVATION: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "size is greater than available space")); (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); break; default: (void) zfs_standard_error(hdl, err, errbuf); break; } break; case EBUSY: (void) zfs_standard_error(hdl, EBUSY, errbuf); break; case EROFS: (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); break; case ENOTSUP: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool and or dataset must be upgraded to set this " "property or value")); (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); break; case ERANGE: if (prop =3D=3D ZFS_PROP_COMPRESSION) { (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "property setting is not allowed on " "bootable datasets")); (void) zfs_error(hdl, EZFS_NOTSUP, errbuf); } else { (void) zfs_standard_error(hdl, err, errbuf); } break; case EINVAL: if (prop =3D=3D ZPROP_INVAL) { (void) zfs_error(hdl, EZFS_BADPROP, errbuf); } else { (void) zfs_standard_error(hdl, err, errbuf); } break; case EOVERFLOW: /* * This platform can't address a volume this big. */ #ifdef _ILP32 if (prop =3D=3D ZFS_PROP_VOLSIZE) { (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); break; } #endif /* FALLTHROUGH */ default: (void) zfs_standard_error(hdl, err, errbuf); } } /* * Given a property name and value, set the property for the given dataset. */ int zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) { zfs_cmd_t zc =3D { 0 }; int ret =3D -1; prop_changelist_t *cl =3D NULL; char errbuf[1024]; libzfs_handle_t *hdl =3D zhp->zfs_hdl; nvlist_t *nvl =3D NULL, *realprops; zfs_prop_t prop; boolean_t do_prefix; uint64_t idx; int added_resv; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), zhp->zfs_name); if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) !=3D 0 || nvlist_add_string(nvl, propname, propval) !=3D 0) { (void) no_memory(hdl); goto error; } if ((realprops =3D zfs_valid_proplist(hdl, zhp->zfs_type, nvl, zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) =3D=3D NULL) goto error; nvlist_free(nvl); nvl =3D realprops; prop =3D zfs_name_to_prop(propname); /* We don't support those properties on FreeBSD. */ switch (prop) { case ZFS_PROP_DEVICES: case ZFS_PROP_ISCSIOPTIONS: case ZFS_PROP_XATTR: case ZFS_PROP_VSCAN: case ZFS_PROP_NBMAND: case ZFS_PROP_MLSLABEL: (void) snprintf(errbuf, sizeof (errbuf), "property '%s' not supported on FreeBSD", propname); ret =3D zfs_error(hdl, EZFS_PERM, errbuf); goto error; } if (prop =3D=3D ZFS_PROP_VOLSIZE) { if ((added_resv =3D zfs_add_synthetic_resv(zhp, nvl)) =3D=3D -1) goto error; } if ((cl =3D changelist_gather(zhp, prop, 0, 0)) =3D=3D NULL) goto error; if (prop =3D=3D ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "child dataset with inherited mountpoint is used " "in a non-global zone")); ret =3D zfs_error(hdl, EZFS_ZONED, errbuf); goto error; } /* * If the dataset's canmount property is being set to noauto, * then we want to prevent unmounting & remounting it. */ do_prefix =3D !((prop =3D=3D ZFS_PROP_CANMOUNT) && (zprop_string_to_index(prop, propval, &idx, ZFS_TYPE_DATASET) =3D=3D 0) && (idx =3D=3D ZFS_CANMOUNT_NOAUTO)); if (do_prefix && (ret =3D changelist_prefix(cl)) !=3D 0) goto error; /* * Execute the corresponding ioctl() to set this property. */ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); if (zcmd_write_src_nvlist(hdl, &zc, nvl) !=3D 0) goto error; ret =3D zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); if (ret !=3D 0) { zfs_setprop_error(hdl, prop, errno, errbuf); if (added_resv && errno =3D=3D ENOSPC) { /* clean up the volsize property we tried to set */ uint64_t old_volsize =3D zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); nvlist_free(nvl); zcmd_free_nvlists(&zc); if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) !=3D 0) goto error; if (nvlist_add_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE), old_volsize) !=3D 0) goto error; if (zcmd_write_src_nvlist(hdl, &zc, nvl) !=3D 0) goto error; (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); } } else { if (do_prefix) ret =3D changelist_postfix(cl); /* * Refresh the statistics so the new property value * is reflected. */ if (ret =3D=3D 0) (void) get_stats(zhp); } error: nvlist_free(nvl); zcmd_free_nvlists(&zc); if (cl) changelist_free(cl); return (ret); } /* * Given a property, inherit the value from the parent dataset, or if recei= ved * is TRUE, revert to the received value, if any. */ int zfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t receive= d) { zfs_cmd_t zc =3D { 0 }; int ret; prop_changelist_t *cl; libzfs_handle_t *hdl =3D zhp->zfs_hdl; char errbuf[1024]; zfs_prop_t prop; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot inherit %s for '%s'"), propname, zhp->zfs_name); zc.zc_cookie =3D received; if ((prop =3D zfs_name_to_prop(propname)) =3D=3D ZPROP_INVAL) { /* * For user properties, the amount of work we have to do is very * small, so just do it here. */ if (!zfs_prop_user(propname)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid property")); return (zfs_error(hdl, EZFS_BADPROP, errbuf)); } (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) !=3D 0) return (zfs_standard_error(hdl, errno, errbuf)); return (0); } /* * Verify that this property is inheritable. */ if (zfs_prop_readonly(prop)) return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); if (!zfs_prop_inheritable(prop) && !received) return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); /* * Check to see if the value applies to this type */ if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); /* * Normalize the name, to get rid of shorthand abbreviations. */ propname =3D zfs_prop_to_name(prop); (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); if (prop =3D=3D ZFS_PROP_MOUNTPOINT && getzoneid() =3D=3D GLOBAL_ZONEID && zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "dataset is used in a non-global zone")); return (zfs_error(hdl, EZFS_ZONED, errbuf)); } /* * Determine datasets which will be affected by this change, if any. */ if ((cl =3D changelist_gather(zhp, prop, 0, 0)) =3D=3D NULL) return (-1); if (prop =3D=3D ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "child dataset with inherited mountpoint is used " "in a non-global zone")); ret =3D zfs_error(hdl, EZFS_ZONED, errbuf); goto error; } if ((ret =3D changelist_prefix(cl)) !=3D 0) goto error; if ((ret =3D zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) !=3D 0) { return (zfs_standard_error(hdl, errno, errbuf)); } else { if ((ret =3D changelist_postfix(cl)) !=3D 0) goto error; /* * Refresh the statistics so the new property is reflected. */ (void) get_stats(zhp); } error: changelist_free(cl); return (ret); } /* * True DSL properties are stored in an nvlist. The following two function= s * extract them appropriately. */ static uint64_t getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) { nvlist_t *nv; uint64_t value; *source =3D NULL; if (nvlist_lookup_nvlist(zhp->zfs_props, zfs_prop_to_name(prop), &nv) =3D=3D 0) { verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) =3D=3D 0); (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); } else { verify(!zhp->zfs_props_table || zhp->zfs_props_table[prop] =3D=3D B_TRUE); value =3D zfs_prop_default_numeric(prop); *source =3D ""; } return (value); } static char * getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) { nvlist_t *nv; char *value; *source =3D NULL; if (nvlist_lookup_nvlist(zhp->zfs_props, zfs_prop_to_name(prop), &nv) =3D=3D 0) { verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) =3D=3D 0); (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); } else { verify(!zhp->zfs_props_table || zhp->zfs_props_table[prop] =3D=3D B_TRUE); if ((value =3D (char *)zfs_prop_default_string(prop)) =3D=3D NULL) value =3D ""; *source =3D ""; } return (value); } static boolean_t zfs_is_recvd_props_mode(zfs_handle_t *zhp) { return (zhp->zfs_props =3D=3D zhp->zfs_recvd_props); } static void zfs_set_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) { *cookie =3D (uint64_t)(uintptr_t)zhp->zfs_props; zhp->zfs_props =3D zhp->zfs_recvd_props; } static void zfs_unset_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) { zhp->zfs_props =3D (nvlist_t *)(uintptr_t)*cookie; *cookie =3D 0; } /* * Internal function for getting a numeric property. Both zfs_prop_get() a= nd * zfs_prop_get_int() are built using this interface. * * Certain properties can be overridden using 'mount -o'. In this case, sc= an * the contents of the /etc/mnttab entry, searching for the appropriate opt= ions. * If they differ from the on-disk values, report the current values and ma= rk * the source "temporary". */ static int get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *sr= c, char **source, uint64_t *val) { zfs_cmd_t zc =3D { 0 }; nvlist_t *zplprops =3D NULL; struct mnttab mnt; char *mntopt_on =3D NULL; char *mntopt_off =3D NULL; boolean_t received =3D zfs_is_recvd_props_mode(zhp); *source =3D NULL; switch (prop) { case ZFS_PROP_ATIME: mntopt_on =3D MNTOPT_ATIME; mntopt_off =3D MNTOPT_NOATIME; break; case ZFS_PROP_DEVICES: mntopt_on =3D MNTOPT_DEVICES; mntopt_off =3D MNTOPT_NODEVICES; break; case ZFS_PROP_EXEC: mntopt_on =3D MNTOPT_EXEC; mntopt_off =3D MNTOPT_NOEXEC; break; case ZFS_PROP_READONLY: mntopt_on =3D MNTOPT_RO; mntopt_off =3D MNTOPT_RW; break; case ZFS_PROP_SETUID: mntopt_on =3D MNTOPT_SETUID; mntopt_off =3D MNTOPT_NOSETUID; break; case ZFS_PROP_XATTR: mntopt_on =3D MNTOPT_XATTR; mntopt_off =3D MNTOPT_NOXATTR; break; case ZFS_PROP_NBMAND: mntopt_on =3D MNTOPT_NBMAND; mntopt_off =3D MNTOPT_NONBMAND; break; } /* * Because looking up the mount options is potentially expensive * (iterating over all of /etc/mnttab), we defer its calculation until * we're looking up a property which requires its presence. */ if (!zhp->zfs_mntcheck && (mntopt_on !=3D NULL || prop =3D=3D ZFS_PROP_MOUNTED)) { libzfs_handle_t *hdl =3D zhp->zfs_hdl; struct mnttab entry; if (libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) =3D=3D 0) { zhp->zfs_mntopts =3D zfs_strdup(hdl, entry.mnt_mntopts); if (zhp->zfs_mntopts =3D=3D NULL) return (-1); } zhp->zfs_mntcheck =3D B_TRUE; } if (zhp->zfs_mntopts =3D=3D NULL) mnt.mnt_mntopts =3D ""; else mnt.mnt_mntopts =3D zhp->zfs_mntopts; switch (prop) { case ZFS_PROP_ATIME: case ZFS_PROP_DEVICES: case ZFS_PROP_EXEC: case ZFS_PROP_READONLY: case ZFS_PROP_SETUID: case ZFS_PROP_XATTR: case ZFS_PROP_NBMAND: *val =3D getprop_uint64(zhp, prop, source); if (received) break; if (hasmntopt(&mnt, mntopt_on) && !*val) { *val =3D B_TRUE; if (src) *src =3D ZPROP_SRC_TEMPORARY; } else if (hasmntopt(&mnt, mntopt_off) && *val) { *val =3D B_FALSE; if (src) *src =3D ZPROP_SRC_TEMPORARY; } break; case ZFS_PROP_CANMOUNT: case ZFS_PROP_VOLSIZE: case ZFS_PROP_QUOTA: case ZFS_PROP_REFQUOTA: case ZFS_PROP_RESERVATION: case ZFS_PROP_REFRESERVATION: *val =3D getprop_uint64(zhp, prop, source); if (*source =3D=3D NULL) { /* not default, must be local */ *source =3D zhp->zfs_name; } break; case ZFS_PROP_MOUNTED: *val =3D (zhp->zfs_mntopts !=3D NULL); break; case ZFS_PROP_NUMCLONES: *val =3D zhp->zfs_dmustats.dds_num_clones; break; case ZFS_PROP_VERSION: case ZFS_PROP_NORMALIZE: case ZFS_PROP_UTF8ONLY: case ZFS_PROP_CASE: if (!zfs_prop_valid_for_type(prop, zhp->zfs_head_type) || zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) !=3D 0) return (-1); (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) { zcmd_free_nvlists(&zc); return (-1); } if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) !=3D 0 || nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop), val) !=3D 0) { zcmd_free_nvlists(&zc); return (-1); } if (zplprops) nvlist_free(zplprops); zcmd_free_nvlists(&zc); break; default: switch (zfs_prop_get_type(prop)) { case PROP_TYPE_NUMBER: case PROP_TYPE_INDEX: *val =3D getprop_uint64(zhp, prop, source); /* * If we tried to use a default value for a * readonly property, it means that it was not * present. */ if (zfs_prop_readonly(prop) && *source !=3D NULL && (*source)[0] =3D=3D '\0') { *source =3D NULL; } break; case PROP_TYPE_STRING: default: zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, "cannot get non-numeric property")); return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN, "internal error"))); } } return (0); } /* * Calculate the source type, given the raw source string. */ static void get_source(zfs_handle_t *zhp, zprop_source_t *srctype, char *source, char *statbuf, size_t statlen) { if (statbuf =3D=3D NULL || *srctype =3D=3D ZPROP_SRC_TEMPORARY) return; if (source =3D=3D NULL) { *srctype =3D ZPROP_SRC_NONE; } else if (source[0] =3D=3D '\0') { *srctype =3D ZPROP_SRC_DEFAULT; } else if (strstr(source, ZPROP_SOURCE_VAL_RECVD) !=3D NULL) { *srctype =3D ZPROP_SRC_RECEIVED; } else { if (strcmp(source, zhp->zfs_name) =3D=3D 0) { *srctype =3D ZPROP_SRC_LOCAL; } else { (void) strlcpy(statbuf, source, statlen); *srctype =3D ZPROP_SRC_INHERITED; } } } int zfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf, size_t proplen, boolean_t literal) { zfs_prop_t prop; int err =3D 0; if (zhp->zfs_recvd_props =3D=3D NULL) if (get_recvd_props_ioctl(zhp) !=3D 0) return (-1); prop =3D zfs_name_to_prop(propname); if (prop !=3D ZPROP_INVAL) { uint64_t cookie; if (!nvlist_exists(zhp->zfs_recvd_props, propname)) return (-1); zfs_set_recvd_props_mode(zhp, &cookie); err =3D zfs_prop_get(zhp, prop, propbuf, proplen, NULL, NULL, 0, literal); zfs_unset_recvd_props_mode(zhp, &cookie); } else { nvlist_t *propval; char *recvdval; if (nvlist_lookup_nvlist(zhp->zfs_recvd_props, propname, &propval) !=3D 0) return (-1); verify(nvlist_lookup_string(propval, ZPROP_VALUE, &recvdval) =3D=3D 0); (void) strlcpy(propbuf, recvdval, proplen); } return (err =3D=3D 0 ? 0 : -1); } static int get_clones_string(zfs_handle_t *zhp, char *propbuf, size_t proplen) { nvlist_t *value; nvpair_t *pair; value =3D zfs_get_clones_nvl(zhp); if (value =3D=3D NULL) return (-1); propbuf[0] =3D '\0'; for (pair =3D nvlist_next_nvpair(value, NULL); pair !=3D NULL; pair =3D nvlist_next_nvpair(value, pair)) { if (propbuf[0] !=3D '\0') (void) strlcat(propbuf, ",", proplen); (void) strlcat(propbuf, nvpair_name(pair), proplen); } return (0); } struct get_clones_arg { uint64_t numclones; nvlist_t *value; const char *origin; char buf[ZFS_MAXNAMELEN]; }; int get_clones_cb(zfs_handle_t *zhp, void *arg) { struct get_clones_arg *gca =3D arg; if (gca->numclones =3D=3D 0) { zfs_close(zhp); return (0); } if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, gca->buf, sizeof (gca->buf), NULL, NULL, 0, B_TRUE) !=3D 0) goto out; if (strcmp(gca->buf, gca->origin) =3D=3D 0) { if (nvlist_add_boolean(gca->value, zfs_get_name(zhp)) !=3D 0) { zfs_close(zhp); return (no_memory(zhp->zfs_hdl)); } gca->numclones--; } out: (void) zfs_iter_children(zhp, get_clones_cb, gca); zfs_close(zhp); return (0); } nvlist_t * zfs_get_clones_nvl(zfs_handle_t *zhp) { nvlist_t *nv, *value; if (nvlist_lookup_nvlist(zhp->zfs_props, zfs_prop_to_name(ZFS_PROP_CLONES), &nv) !=3D 0) { struct get_clones_arg gca; /* * if this is a snapshot, then the kernel wasn't able * to get the clones. Do it by slowly iterating. */ if (zhp->zfs_type !=3D ZFS_TYPE_SNAPSHOT) return (NULL); if (nvlist_alloc(&nv, NV_UNIQUE_NAME, 0) !=3D 0) return (NULL); if (nvlist_alloc(&value, NV_UNIQUE_NAME, 0) !=3D 0) { nvlist_free(nv); return (NULL); } gca.numclones =3D zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES); gca.value =3D value; gca.origin =3D zhp->zfs_name; if (gca.numclones !=3D 0) { zfs_handle_t *root; char pool[ZFS_MAXNAMELEN]; char *cp =3D pool; /* get the pool name */ (void) strlcpy(pool, zhp->zfs_name, sizeof (pool)); (void) strsep(&cp, "/@"); root =3D zfs_open(zhp->zfs_hdl, pool, ZFS_TYPE_FILESYSTEM); (void) get_clones_cb(root, &gca); } if (gca.numclones !=3D 0 || nvlist_add_nvlist(nv, ZPROP_VALUE, value) !=3D 0 || nvlist_add_nvlist(zhp->zfs_props, zfs_prop_to_name(ZFS_PROP_CLONES), nv) !=3D 0) { nvlist_free(nv); nvlist_free(value); return (NULL); } nvlist_free(nv); nvlist_free(value); verify(0 =3D=3D nvlist_lookup_nvlist(zhp->zfs_props, zfs_prop_to_name(ZFS_PROP_CLONES), &nv)); } verify(nvlist_lookup_nvlist(nv, ZPROP_VALUE, &value) =3D=3D 0); return (value); } /* * Retrieve a property from the given object. If 'literal' is specified, t= hen * numbers are left as exact values. Otherwise, numbers are converted to a * human-readable form. * * Returns 0 on success, or -1 on error. */ int zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t prop= len, zprop_source_t *src, char *statbuf, size_t statlen, boolean_t literal) { char *source =3D NULL; uint64_t val; char *str; const char *strval; boolean_t received =3D zfs_is_recvd_props_mode(zhp); /* * Check to see if this property applies to our object */ if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) return (-1); if (received && zfs_prop_readonly(prop)) return (-1); if (src) *src =3D ZPROP_SRC_NONE; switch (prop) { case ZFS_PROP_CREATION: /* * 'creation' is a time_t stored in the statistics. We convert * this into a string unless 'literal' is specified. */ { val =3D getprop_uint64(zhp, prop, &source); time_t time =3D (time_t)val; struct tm t; if (literal || localtime_r(&time, &t) =3D=3D NULL || strftime(propbuf, proplen, "%a %b %e %k:%M %Y", &t) =3D=3D 0) (void) snprintf(propbuf, proplen, "%llu", val); } break; case ZFS_PROP_MOUNTPOINT: /* * Getting the precise mountpoint can be tricky. * * - for 'none' or 'legacy', return those values. * - for inherited mountpoints, we want to take everything * after our ancestor and append it to the inherited value. * * If the pool has an alternate root, we want to prepend that * root to any values we return. */ str =3D getprop_string(zhp, prop, &source); if (str[0] =3D=3D '/') { char buf[MAXPATHLEN]; char *root =3D buf; const char *relpath; /* * If we inherit the mountpoint, even from a dataset * with a received value, the source will be the path of * the dataset we inherit from. If source is * ZPROP_SOURCE_VAL_RECVD, the received value is not * inherited. */ if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) =3D=3D 0) { relpath =3D ""; } else { relpath =3D zhp->zfs_name + strlen(source); if (relpath[0] =3D=3D '/') relpath++; } if ((zpool_get_prop(zhp->zpool_hdl, ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL)) || (strcmp(root, "-") =3D=3D 0)) root[0] =3D '\0'; /* * Special case an alternate root of '/'. This will * avoid having multiple leading slashes in the * mountpoint path. */ if (strcmp(root, "/") =3D=3D 0) root++; /* * If the mountpoint is '/' then skip over this * if we are obtaining either an alternate root or * an inherited mountpoint. */ if (str[1] =3D=3D '\0' && (root[0] !=3D '\0' || relpath[0] !=3D '\0')) str++; if (relpath[0] =3D=3D '\0') (void) snprintf(propbuf, proplen, "%s%s", root, str); else (void) snprintf(propbuf, proplen, "%s%s%s%s", root, str, relpath[0] =3D=3D '@' ? "" : "/", relpath); } else { /* 'legacy' or 'none' */ (void) strlcpy(propbuf, str, proplen); } break; case ZFS_PROP_ORIGIN: (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), proplen); /* * If there is no parent at all, return failure to indicate that * it doesn't apply to this dataset. */ if (propbuf[0] =3D=3D '\0') return (-1); break; case ZFS_PROP_CLONES: if (get_clones_string(zhp, propbuf, proplen) !=3D 0) return (-1); break; case ZFS_PROP_QUOTA: case ZFS_PROP_REFQUOTA: case ZFS_PROP_RESERVATION: case ZFS_PROP_REFRESERVATION: if (get_numeric_property(zhp, prop, src, &source, &val) !=3D 0) return (-1); /* * If quota or reservation is 0, we translate this into 'none' * (unless literal is set), and indicate that it's the default * value. Otherwise, we print the number nicely and indicate * that its set locally. */ if (val =3D=3D 0) { if (literal) (void) strlcpy(propbuf, "0", proplen); else (void) strlcpy(propbuf, "none", proplen); } else { if (literal) (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val); else zfs_nicenum(val, propbuf, proplen); } break; case ZFS_PROP_REFRATIO: case ZFS_PROP_COMPRESSRATIO: if (get_numeric_property(zhp, prop, src, &source, &val) !=3D 0) return (-1); (void) snprintf(propbuf, proplen, "%llu.%02llux", (u_longlong_t)(val / 100), (u_longlong_t)(val % 100)); break; case ZFS_PROP_TYPE: switch (zhp->zfs_type) { case ZFS_TYPE_FILESYSTEM: str =3D "filesystem"; break; case ZFS_TYPE_VOLUME: str =3D "volume"; break; case ZFS_TYPE_SNAPSHOT: str =3D "snapshot"; break; default: abort(); } (void) snprintf(propbuf, proplen, "%s", str); break; case ZFS_PROP_MOUNTED: /* * The 'mounted' property is a pseudo-property that described * whether the filesystem is currently mounted. Even though * it's a boolean value, the typical values of "on" and "off" * don't make sense, so we translate to "yes" and "no". */ if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, src, &source, &val) !=3D 0) return (-1); if (val) (void) strlcpy(propbuf, "yes", proplen); else (void) strlcpy(propbuf, "no", proplen); break; case ZFS_PROP_NAME: /* * The 'name' property is a pseudo-property derived from the * dataset name. It is presented as a real property to simplify * consumers. */ (void) strlcpy(propbuf, zhp->zfs_name, proplen); break; case ZFS_PROP_MLSLABEL: { #ifdef sun m_label_t *new_sl =3D NULL; char *ascii =3D NULL; /* human readable label */ (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), proplen); if (literal || (strcasecmp(propbuf, ZFS_MLSLABEL_DEFAULT) =3D=3D 0)) break; /* * Try to translate the internal hex string to * human-readable output. If there are any * problems just use the hex string. */ if (str_to_label(propbuf, &new_sl, MAC_LABEL, L_NO_CORRECTION, NULL) =3D=3D -1) { m_label_free(new_sl); break; } if (label_to_str(new_sl, &ascii, M_LABEL, DEF_NAMES) !=3D 0) { if (ascii) free(ascii); m_label_free(new_sl); break; } m_label_free(new_sl); (void) strlcpy(propbuf, ascii, proplen); free(ascii); #else /* !sun */ propbuf[0] =3D '\0'; #endif /* !sun */ } break; case ZFS_PROP_GUID: /* * GUIDs are stored as numbers, but they are identifiers. * We don't want them to be pretty printed, because pretty * printing mangles the ID into a truncated and useless value. */ if (get_numeric_property(zhp, prop, src, &source, &val) !=3D 0) return (-1); (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val); break; default: switch (zfs_prop_get_type(prop)) { case PROP_TYPE_NUMBER: if (get_numeric_property(zhp, prop, src, &source, &val) !=3D 0) return (-1); if (literal) (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val); else zfs_nicenum(val, propbuf, proplen); break; case PROP_TYPE_STRING: (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), proplen); break; case PROP_TYPE_INDEX: if (get_numeric_property(zhp, prop, src, &source, &val) !=3D 0) return (-1); if (zfs_prop_index_to_string(prop, val, &strval) !=3D 0) return (-1); (void) strlcpy(propbuf, strval, proplen); break; default: abort(); } } get_source(zhp, src, source, statbuf, statlen); return (0); } /* * Utility function to get the given numeric property. Does no validation = that * the given property is the appropriate type; should only be used with * hard-coded property types. */ uint64_t zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) { char *source; uint64_t val; (void) get_numeric_property(zhp, prop, NULL, &source, &val); return (val); } int zfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val) { char buf[64]; (void) snprintf(buf, sizeof (buf), "%llu", (longlong_t)val); return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf)); } /* * Similar to zfs_prop_get(), but returns the value as an integer. */ int zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, zprop_source_t *src, char *statbuf, size_t statlen) { char *source; /* * Check to see if this property applies to our object */ if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) { return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE, dgettext(TEXT_DOMAIN, "cannot get property '%s'"), zfs_prop_to_name(prop))); } if (src) *src =3D ZPROP_SRC_NONE; if (get_numeric_property(zhp, prop, src, &source, value) !=3D 0) return (-1); get_source(zhp, src, source, statbuf, statlen); return (0); } static int idmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser, char **domainp, idmap_rid_t *ridp) { #ifdef sun idmap_get_handle_t *get_hdl =3D NULL; idmap_stat status; int err =3D EINVAL; if (idmap_get_create(&get_hdl) !=3D IDMAP_SUCCESS) goto out; if (isuser) { err =3D idmap_get_sidbyuid(get_hdl, id, IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); } else { err =3D idmap_get_sidbygid(get_hdl, id, IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); } if (err =3D=3D IDMAP_SUCCESS && idmap_get_mappings(get_hdl) =3D=3D IDMAP_SUCCESS && status =3D=3D IDMAP_SUCCESS) err =3D 0; else err =3D EINVAL; out: if (get_hdl) idmap_get_destroy(get_hdl); return (err); #else /* !sun */ assert(!"invalid code path"); #endif /* !sun */ } /* * convert the propname into parameters needed by kernel * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829 * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789 */ static int userquota_propname_decode(const char *propname, boolean_t zoned, zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *rid= p) { zfs_userquota_prop_t type; char *cp, *end; char *numericsid =3D NULL; boolean_t isuser; domain[0] =3D '\0'; /* Figure out the property type ({user|group}{quota|space}) */ for (type =3D 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) { if (strncmp(propname, zfs_userquota_prop_prefixes[type], strlen(zfs_userquota_prop_prefixes[type])) =3D=3D 0) break; } if (type =3D=3D ZFS_NUM_USERQUOTA_PROPS) return (EINVAL); *typep =3D type; isuser =3D (type =3D=3D ZFS_PROP_USERQUOTA || type =3D=3D ZFS_PROP_USERUSED); cp =3D strchr(propname, '@') + 1; if (strchr(cp, '@')) { #ifdef sun /* * It's a SID name (eg "user@domain") that needs to be * turned into S-1-domainID-RID. */ directory_error_t e; if (zoned && getzoneid() =3D=3D GLOBAL_ZONEID) return (ENOENT); if (isuser) { e =3D directory_sid_from_user_name(NULL, cp, &numericsid); } else { e =3D directory_sid_from_group_name(NULL, cp, &numericsid); } if (e !=3D NULL) { directory_error_free(e); return (ENOENT); } if (numericsid =3D=3D NULL) return (ENOENT); cp =3D numericsid; /* will be further decoded below */ #else /* !sun */ return (ENOENT); #endif /* !sun */ } if (strncmp(cp, "S-1-", 4) =3D=3D 0) { /* It's a numeric SID (eg "S-1-234-567-89") */ (void) strlcpy(domain, cp, domainlen); cp =3D strrchr(domain, '-'); *cp =3D '\0'; cp++; errno =3D 0; *ridp =3D strtoull(cp, &end, 10); if (numericsid) { free(numericsid); numericsid =3D NULL; } if (errno !=3D 0 || *end !=3D '\0') return (EINVAL); } else if (!isdigit(*cp)) { /* * It's a user/group name (eg "user") that needs to be * turned into a uid/gid */ if (zoned && getzoneid() =3D=3D GLOBAL_ZONEID) return (ENOENT); if (isuser) { struct passwd *pw; pw =3D getpwnam(cp); if (pw =3D=3D NULL) return (ENOENT); *ridp =3D pw->pw_uid; } else { struct group *gr; gr =3D getgrnam(cp); if (gr =3D=3D NULL) return (ENOENT); *ridp =3D gr->gr_gid; } } else { /* It's a user/group ID (eg "12345"). */ uid_t id =3D strtoul(cp, &end, 10); idmap_rid_t rid; char *mapdomain; if (*end !=3D '\0') return (EINVAL); if (id > MAXUID) { /* It's an ephemeral ID. */ if (idmap_id_to_numeric_domain_rid(id, isuser, &mapdomain, &rid) !=3D 0) return (ENOENT); (void) strlcpy(domain, mapdomain, domainlen); *ridp =3D rid; } else { *ridp =3D id; } } ASSERT3P(numericsid, =3D=3D, NULL); return (0); } static int zfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname, uint64_t *propvalue, zfs_userquota_prop_t *typep) { int err; zfs_cmd_t zc =3D { 0 }; (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); err =3D userquota_propname_decode(propname, zfs_prop_get_int(zhp, ZFS_PROP_ZONED), typep, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid); zc.zc_objset_type =3D *typep; if (err) return (err); err =3D ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_ONE, &zc); if (err) return (err); *propvalue =3D zc.zc_cookie; return (0); } int zfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname, uint64_t *propvalue) { zfs_userquota_prop_t type; return (zfs_prop_get_userquota_common(zhp, propname, propvalue, &type)); } int zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname, char *propbuf, int proplen, boolean_t literal) { int err; uint64_t propvalue; zfs_userquota_prop_t type; err =3D zfs_prop_get_userquota_common(zhp, propname, &propvalue, &type); if (err) return (err); if (literal) { (void) snprintf(propbuf, proplen, "%llu", propvalue); } else if (propvalue =3D=3D 0 && (type =3D=3D ZFS_PROP_USERQUOTA || type =3D=3D ZFS_PROP_GROUPQUOTA)) { (void) strlcpy(propbuf, "none", proplen); } else { zfs_nicenum(propvalue, propbuf, proplen); } return (0); } int zfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname, uint64_t *propvalue) { int err; zfs_cmd_t zc =3D { 0 }; const char *snapname; (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); snapname =3D strchr(propname, '@') + 1; if (strchr(snapname, '@')) { (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); } else { /* snapname is the short name, append it to zhp's fsname */ char *cp; (void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value)); cp =3D strchr(zc.zc_value, '@'); if (cp !=3D NULL) *cp =3D '\0'; (void) strlcat(zc.zc_value, "@", sizeof (zc.zc_value)); (void) strlcat(zc.zc_value, snapname, sizeof (zc.zc_value)); } err =3D ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_WRITTEN, &zc); if (err) return (err); *propvalue =3D zc.zc_cookie; return (0); } int zfs_prop_get_written(zfs_handle_t *zhp, const char *propname, char *propbuf, int proplen, boolean_t literal) { int err; uint64_t propvalue; err =3D zfs_prop_get_written_int(zhp, propname, &propvalue); if (err) return (err); if (literal) { (void) snprintf(propbuf, proplen, "%llu", propvalue); } else { zfs_nicenum(propvalue, propbuf, proplen); } return (0); } int zfs_get_snapused_int(zfs_handle_t *firstsnap, zfs_handle_t *lastsnap, uint64_t *usedp) { int err; zfs_cmd_t zc =3D { 0 }; (void) strlcpy(zc.zc_name, lastsnap->zfs_name, sizeof (zc.zc_name)); (void) strlcpy(zc.zc_value, firstsnap->zfs_name, sizeof (zc.zc_value)); err =3D ioctl(lastsnap->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_SNAPS, &zc); if (err) return (err); *usedp =3D zc.zc_cookie; return (0); } /* * Returns the name of the given zfs handle. */ const char * zfs_get_name(const zfs_handle_t *zhp) { return (zhp->zfs_name); } /* * Returns the type of the given zfs handle. */ zfs_type_t zfs_get_type(const zfs_handle_t *zhp) { return (zhp->zfs_type); } /* * Is one dataset name a child dataset of another? * * Needs to handle these cases: * Dataset 1 "a/foo" "a/foo" "a/foo" "a/foo" * Dataset 2 "a/fo" "a/foobar" "a/bar/baz" "a/foo/bar" * Descendant? No. No. No. Yes. */ static boolean_t is_descendant(const char *ds1, const char *ds2) { size_t d1len =3D strlen(ds1); /* ds2 can't be a descendant if it's smaller */ if (strlen(ds2) < d1len) return (B_FALSE); /* otherwise, compare strings and verify that there's a '/' char */ return (ds2[d1len] =3D=3D '/' && (strncmp(ds1, ds2, d1len) =3D=3D 0)); } /* * Given a complete name, return just the portion that refers to the parent= . * Will return -1 if there is no parent (path is just the name of the * pool). */ static int parent_name(const char *path, char *buf, size_t buflen) { char *slashp; (void) strlcpy(buf, path, buflen); if ((slashp =3D strrchr(buf, '/')) =3D=3D NULL) return (-1); *slashp =3D '\0'; return (0); } /* * If accept_ancestor is false, then check to make sure that the given path= has * a parent, and that it exists. If accept_ancestor is true, then find the * closest existing ancestor for the given path. In prefixlen return the * length of already existing prefix of the given path. We also fetch the * 'zoned' property, which is used to validate property settings when creat= ing * new datasets. */ static int check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned, boolean_t accept_ancestor, int *prefixlen) { zfs_cmd_t zc =3D { 0 }; char parent[ZFS_MAXNAMELEN]; char *slash; zfs_handle_t *zhp; char errbuf[1024]; uint64_t is_zoned; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot create '%s'"), path); /* get parent, and check to see if this is just a pool */ if (parent_name(path, parent, sizeof (parent)) !=3D 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "missing dataset name")); return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); } /* check to see if the pool exists */ if ((slash =3D strchr(parent, '/')) =3D=3D NULL) slash =3D parent + strlen(parent); (void) strncpy(zc.zc_name, parent, slash - parent); zc.zc_name[slash - parent] =3D '\0'; if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) !=3D 0 && errno =3D=3D ENOENT) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool '%s'"), zc.zc_name); return (zfs_error(hdl, EZFS_NOENT, errbuf)); } /* check to see if the parent dataset exists */ while ((zhp =3D make_dataset_handle(hdl, parent)) =3D=3D NULL) { if (errno =3D=3D ENOENT && accept_ancestor) { /* * Go deeper to find an ancestor, give up on top level. */ if (parent_name(parent, parent, sizeof (parent)) !=3D 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool '%s'"), zc.zc_name); return (zfs_error(hdl, EZFS_NOENT, errbuf)); } } else if (errno =3D=3D ENOENT) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "parent does not exist")); return (zfs_error(hdl, EZFS_NOENT, errbuf)); } else return (zfs_standard_error(hdl, errno, errbuf)); } is_zoned =3D zfs_prop_get_int(zhp, ZFS_PROP_ZONED); if (zoned !=3D NULL) *zoned =3D is_zoned; /* we are in a non-global zone, but parent is in the global zone */ if (getzoneid() !=3D GLOBAL_ZONEID && !is_zoned) { (void) zfs_standard_error(hdl, EPERM, errbuf); zfs_close(zhp); return (-1); } /* make sure parent is a filesystem */ if (zfs_get_type(zhp) !=3D ZFS_TYPE_FILESYSTEM) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "parent is not a filesystem")); (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); zfs_close(zhp); return (-1); } zfs_close(zhp); if (prefixlen !=3D NULL) *prefixlen =3D strlen(parent); return (0); } /* * Finds whether the dataset of the given type(s) exists. */ boolean_t zfs_dataset_exists(libzfs_handle_t *hdl, const char *path, zfs_type_t types= ) { zfs_handle_t *zhp; if (!zfs_validate_name(hdl, path, types, B_FALSE)) return (B_FALSE); /* * Try to get stats for the dataset, which will tell us if it exists. */ if ((zhp =3D make_dataset_handle(hdl, path)) !=3D NULL) { int ds_type =3D zhp->zfs_type; zfs_close(zhp); if (types & ds_type) return (B_TRUE); } return (B_FALSE); } /* * Given a path to 'target', create all the ancestors between * the prefixlen portion of the path, and the target itself. * Fail if the initial prefixlen-ancestor does not already exist. */ int create_parents(libzfs_handle_t *hdl, char *target, int prefixlen) { zfs_handle_t *h; char *cp; const char *opname; /* make sure prefix exists */ cp =3D target + prefixlen; if (*cp !=3D '/') { assert(strchr(cp, '/') =3D=3D NULL); h =3D zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); } else { *cp =3D '\0'; h =3D zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); *cp =3D '/'; } if (h =3D=3D NULL) return (-1); zfs_close(h); /* * Attempt to create, mount, and share any ancestor filesystems, * up to the prefixlen-long one. */ for (cp =3D target + prefixlen + 1; cp =3D strchr(cp, '/'); *cp =3D '/', cp++) { char *logstr; *cp =3D '\0'; h =3D make_dataset_handle(hdl, target); if (h) { /* it already exists, nothing to do here */ zfs_close(h); continue; } logstr =3D hdl->libzfs_log_str; hdl->libzfs_log_str =3D NULL; if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, NULL) !=3D 0) { hdl->libzfs_log_str =3D logstr; opname =3D dgettext(TEXT_DOMAIN, "create"); goto ancestorerr; } hdl->libzfs_log_str =3D logstr; h =3D zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); if (h =3D=3D NULL) { opname =3D dgettext(TEXT_DOMAIN, "open"); goto ancestorerr; } if (zfs_mount(h, NULL, 0) !=3D 0) { opname =3D dgettext(TEXT_DOMAIN, "mount"); goto ancestorerr; } if (zfs_share(h) !=3D 0) { opname =3D dgettext(TEXT_DOMAIN, "share"); goto ancestorerr; } zfs_close(h); } return (0); ancestorerr: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "failed to %s ancestor '%s'"), opname, target); return (-1); } /* * Creates non-existing ancestors of the given path. */ int zfs_create_ancestors(libzfs_handle_t *hdl, const char *path) { int prefix; char *path_copy; int rc; if (check_parents(hdl, path, NULL, B_TRUE, &prefix) !=3D 0) return (-1); if ((path_copy =3D strdup(path)) !=3D NULL) { rc =3D create_parents(hdl, path_copy, prefix); free(path_copy); } if (path_copy =3D=3D NULL || rc !=3D 0) return (-1); return (0); } /* * Create a new filesystem or volume. */ int zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, nvlist_t *props) { zfs_cmd_t zc =3D { 0 }; int ret; uint64_t size =3D 0; uint64_t blocksize =3D zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); char errbuf[1024]; uint64_t zoned; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot create '%s'"), path); /* validate the path, taking care to note the extended error message */ if (!zfs_validate_name(hdl, path, type, B_TRUE)) return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); /* validate parents exist */ if (check_parents(hdl, path, &zoned, B_FALSE, NULL) !=3D 0) return (-1); /* * The failure modes when creating a dataset of a different type over * one that already exists is a little strange. In particular, if you * try to create a dataset on top of an existing dataset, the ioctl() * will return ENOENT, not EEXIST. To prevent this from happening, we * first try to see if the dataset exists. */ (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); if (zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "dataset already exists")); return (zfs_error(hdl, EZFS_EXISTS, errbuf)); } if (type =3D=3D ZFS_TYPE_VOLUME) zc.zc_objset_type =3D DMU_OST_ZVOL; else zc.zc_objset_type =3D DMU_OST_ZFS; if (props && (props =3D zfs_valid_proplist(hdl, type, props, zoned, NULL, errbuf)) =3D=3D 0) return (-1); if (type =3D=3D ZFS_TYPE_VOLUME) { /* * If we are creating a volume, the size and block size must * satisfy a few restraints. First, the blocksize must be a * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the * volsize must be a multiple of the block size, and cannot be * zero. */ if (props =3D=3D NULL || nvlist_lookup_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) !=3D 0) { nvlist_free(props); zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "missing volume size")); return (zfs_error(hdl, EZFS_BADPROP, errbuf)); } if ((ret =3D nvlist_lookup_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), &blocksize)) !=3D 0) { if (ret =3D=3D ENOENT) { blocksize =3D zfs_prop_default_numeric( ZFS_PROP_VOLBLOCKSIZE); } else { nvlist_free(props); zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "missing volume block size")); return (zfs_error(hdl, EZFS_BADPROP, errbuf)); } } if (size =3D=3D 0) { nvlist_free(props); zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "volume size cannot be zero")); return (zfs_error(hdl, EZFS_BADPROP, errbuf)); } if (size % blocksize !=3D 0) { nvlist_free(props); zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "volume size must be a multiple of volume block " "size")); return (zfs_error(hdl, EZFS_BADPROP, errbuf)); } } if (props && zcmd_write_src_nvlist(hdl, &zc, props) !=3D 0) return (-1); nvlist_free(props); /* create the dataset */ ret =3D zfs_ioctl(hdl, ZFS_IOC_CREATE, &zc); zcmd_free_nvlists(&zc); /* check for failure */ if (ret !=3D 0) { char parent[ZFS_MAXNAMELEN]; (void) parent_name(path, parent, sizeof (parent)); switch (errno) { case ENOENT: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such parent '%s'"), parent); return (zfs_error(hdl, EZFS_NOENT, errbuf)); case EINVAL: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "parent '%s' is not a filesystem"), parent); return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); case EDOM: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "volume block size must be power of 2 from " "%u to %uk"), (uint_t)SPA_MINBLOCKSIZE, (uint_t)SPA_MAXBLOCKSIZE >> 10); return (zfs_error(hdl, EZFS_BADPROP, errbuf)); case ENOTSUP: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be upgraded to set this " "property or value")); return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); #ifdef _ILP32 case EOVERFLOW: /* * This platform can't address a volume this big. */ if (type =3D=3D ZFS_TYPE_VOLUME) return (zfs_error(hdl, EZFS_VOLTOOBIG, errbuf)); #endif /* FALLTHROUGH */ default: return (zfs_standard_error(hdl, errno, errbuf)); } } return (0); } /* * Destroys the given dataset. The caller must make sure that the filesyst= em * isn't mounted, and that there are no active dependents. */ int zfs_destroy(zfs_handle_t *zhp, boolean_t defer) { zfs_cmd_t zc =3D { 0 }; (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); if (ZFS_IS_VOLUME(zhp)) { zc.zc_objset_type =3D DMU_OST_ZVOL; } else { zc.zc_objset_type =3D DMU_OST_ZFS; } zc.zc_defer_destroy =3D defer; if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) !=3D 0) { return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), zhp->zfs_name)); } remove_mountpoint(zhp); return (0); } struct destroydata { nvlist_t *nvl; const char *snapname; }; static int zfs_check_snap_cb(zfs_handle_t *zhp, void *arg) { struct destroydata *dd =3D arg; zfs_handle_t *szhp; char name[ZFS_MAXNAMELEN]; int rv =3D 0; (void) snprintf(name, sizeof (name), "%s@%s", zhp->zfs_name, dd->snapname); szhp =3D make_dataset_handle(zhp->zfs_hdl, name); if (szhp) { verify(nvlist_add_boolean(dd->nvl, name) =3D=3D 0); zfs_close(szhp); } rv =3D zfs_iter_filesystems(zhp, zfs_check_snap_cb, dd); zfs_close(zhp); return (rv); } /* * Destroys all snapshots with the given name in zhp & descendants. */ int zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer) { int ret; struct destroydata dd =3D { 0 }; dd.snapname =3D snapname; verify(nvlist_alloc(&dd.nvl, NV_UNIQUE_NAME, 0) =3D=3D 0); (void) zfs_check_snap_cb(zfs_handle_dup(zhp), &dd); if (nvlist_next_nvpair(dd.nvl, NULL) =3D=3D NULL) { ret =3D zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), zhp->zfs_name, snapname); } else { ret =3D zfs_destroy_snaps_nvl(zhp, dd.nvl, defer); } nvlist_free(dd.nvl); return (ret); } /* * Destroys all the snapshots named in the nvlist. They must be underneath * the zhp (either snapshots of it, or snapshots of its descendants). */ int zfs_destroy_snaps_nvl(zfs_handle_t *zhp, nvlist_t *snaps, boolean_t defer) { int ret; zfs_cmd_t zc =3D { 0 }; (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); if (zcmd_write_src_nvlist(zhp->zfs_hdl, &zc, snaps) !=3D 0) return (-1); zc.zc_defer_destroy =3D defer; ret =3D zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY_SNAPS_NVL, &zc); if (ret !=3D 0) { char errbuf[1024]; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot destroy snapshots in %s"), zc.zc_name); switch (errno) { case EEXIST: zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, "snapshot is cloned")); return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf)); default: return (zfs_standard_error(zhp->zfs_hdl, errno, errbuf)); } } return (0); } /* * Clones the given dataset. The target must be of the same type as the so= urce. */ int zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) { zfs_cmd_t zc =3D { 0 }; char parent[ZFS_MAXNAMELEN]; int ret; char errbuf[1024]; libzfs_handle_t *hdl =3D zhp->zfs_hdl; zfs_type_t type; uint64_t zoned; assert(zhp->zfs_type =3D=3D ZFS_TYPE_SNAPSHOT); (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot create '%s'"), target); /* validate the target/clone name */ if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE)) return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); /* validate parents exist */ if (check_parents(hdl, target, &zoned, B_FALSE, NULL) !=3D 0) return (-1); (void) parent_name(target, parent, sizeof (parent)); /* do the clone */ if (ZFS_IS_VOLUME(zhp)) { zc.zc_objset_type =3D DMU_OST_ZVOL; type =3D ZFS_TYPE_VOLUME; } else { zc.zc_objset_type =3D DMU_OST_ZFS; type =3D ZFS_TYPE_FILESYSTEM; } if (props) { if ((props =3D zfs_valid_proplist(hdl, type, props, zoned, zhp, errbuf)) =3D=3D NULL) return (-1); if (zcmd_write_src_nvlist(hdl, &zc, props) !=3D 0) { nvlist_free(props); return (-1); } nvlist_free(props); } (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); (void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value)); ret =3D zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CREATE, &zc); zcmd_free_nvlists(&zc); if (ret !=3D 0) { switch (errno) { case ENOENT: /* * The parent doesn't exist. We should have caught this * above, but there may a race condition that has since * destroyed the parent. * * At this point, we don't know whether it's the source * that doesn't exist anymore, or whether the target * dataset doesn't exist. */ zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, "no such parent '%s'"), parent); return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); case EXDEV: zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, "source and target pools differ")); return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, errbuf)); default: return (zfs_standard_error(zhp->zfs_hdl, errno, errbuf)); } } return (ret); } /* * Promotes the given clone fs to be the clone parent. */ int zfs_promote(zfs_handle_t *zhp) { libzfs_handle_t *hdl =3D zhp->zfs_hdl; zfs_cmd_t zc =3D { 0 }; char parent[MAXPATHLEN]; int ret; char errbuf[1024]; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot promote '%s'"), zhp->zfs_name); if (zhp->zfs_type =3D=3D ZFS_TYPE_SNAPSHOT) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "snapshots can not be promoted")); return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); } (void) strlcpy(parent, zhp->zfs_dmustats.dds_origin, sizeof (parent)); if (parent[0] =3D=3D '\0') { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "not a cloned filesystem")); return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); } (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_origin, sizeof (zc.zc_value)); (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); ret =3D zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc); if (ret !=3D 0) { int save_errno =3D errno; switch (save_errno) { case EEXIST: /* There is a conflicting snapshot name. */ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "conflicting snapshot '%s' from parent '%s'"), zc.zc_string, parent); return (zfs_error(hdl, EZFS_EXISTS, errbuf)); default: return (zfs_standard_error(hdl, save_errno, errbuf)); } } return (ret); } /* * Takes a snapshot of the given dataset. */ int zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive, nvlist_t *props) { const char *delim; char parent[ZFS_MAXNAMELEN]; zfs_handle_t *zhp; zfs_cmd_t zc =3D { 0 }; int ret; char errbuf[1024]; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot snapshot '%s'"), path); /* validate the target name */ if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE)) return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); if (props) { if ((props =3D zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT, props, B_FALSE, NULL, errbuf)) =3D=3D NULL) return (-1); if (zcmd_write_src_nvlist(hdl, &zc, props) !=3D 0) { nvlist_free(props); return (-1); } nvlist_free(props); } /* make sure the parent exists and is of the appropriate type */ delim =3D strchr(path, '@'); (void) strncpy(parent, path, delim - path); parent[delim - path] =3D '\0'; if ((zhp =3D zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) =3D=3D NULL) { zcmd_free_nvlists(&zc); return (-1); } (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); (void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value)); if (ZFS_IS_VOLUME(zhp)) zc.zc_objset_type =3D DMU_OST_ZVOL; else zc.zc_objset_type =3D DMU_OST_ZFS; zc.zc_cookie =3D recursive; ret =3D zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SNAPSHOT, &zc); zcmd_free_nvlists(&zc); /* * if it was recursive, the one that actually failed will be in * zc.zc_name. */ if (ret !=3D 0) { (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value); (void) zfs_standard_error(hdl, errno, errbuf); } zfs_close(zhp); return (ret); } /* * Destroy any more recent snapshots. We invoke this callback on any depen= dents * of the snapshot first. If the 'cb_dependent' member is non-zero, then t= his * is a dependent and we should just destroy it without checking the transa= ction * group. */ typedef struct rollback_data { const char *cb_target; /* the snapshot */ uint64_t cb_create; /* creation time reference */ boolean_t cb_error; boolean_t cb_dependent; boolean_t cb_force; } rollback_data_t; static int rollback_destroy(zfs_handle_t *zhp, void *data) { rollback_data_t *cbp =3D data; if (!cbp->cb_dependent) { if (strcmp(zhp->zfs_name, cbp->cb_target) !=3D 0 && zfs_get_type(zhp) =3D=3D ZFS_TYPE_SNAPSHOT && zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > cbp->cb_create) { char *logstr; cbp->cb_dependent =3D B_TRUE; cbp->cb_error |=3D zfs_iter_dependents(zhp, B_FALSE, rollback_destroy, cbp); cbp->cb_dependent =3D B_FALSE; logstr =3D zhp->zfs_hdl->libzfs_log_str; zhp->zfs_hdl->libzfs_log_str =3D NULL; cbp->cb_error |=3D zfs_destroy(zhp, B_FALSE); zhp->zfs_hdl->libzfs_log_str =3D logstr; } } else { /* We must destroy this clone; first unmount it */ prop_changelist_t *clp; clp =3D changelist_gather(zhp, ZFS_PROP_NAME, 0, cbp->cb_force ? MS_FORCE: 0); if (clp =3D=3D NULL || changelist_prefix(clp) !=3D 0) { cbp->cb_error =3D B_TRUE; zfs_close(zhp); return (0); } if (zfs_destroy(zhp, B_FALSE) !=3D 0) cbp->cb_error =3D B_TRUE; else changelist_remove(clp, zhp->zfs_name); (void) changelist_postfix(clp); changelist_free(clp); } zfs_close(zhp); return (0); } /* * Given a dataset, rollback to a specific snapshot, discarding any * data changes since then and making it the active dataset. * * Any snapshots more recent than the target are destroyed, along with * their dependents. */ int zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force) { rollback_data_t cb =3D { 0 }; int err; zfs_cmd_t zc =3D { 0 }; boolean_t restore_resv =3D 0; uint64_t old_volsize, new_volsize; zfs_prop_t resv_prop; assert(zhp->zfs_type =3D=3D ZFS_TYPE_FILESYSTEM || zhp->zfs_type =3D=3D ZFS_TYPE_VOLUME); /* * Destroy all recent snapshots and its dependends. */ cb.cb_force =3D force; cb.cb_target =3D snap->zfs_name; cb.cb_create =3D zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); (void) zfs_iter_children(zhp, rollback_destroy, &cb); if (cb.cb_error) return (-1); /* * Now that we have verified that the snapshot is the latest, * rollback to the given snapshot. */ if (zhp->zfs_type =3D=3D ZFS_TYPE_VOLUME) { if (zfs_which_resv_prop(zhp, &resv_prop) < 0) return (-1); old_volsize =3D zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); restore_resv =3D (old_volsize =3D=3D zfs_prop_get_int(zhp, resv_prop)); } (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); if (ZFS_IS_VOLUME(zhp)) zc.zc_objset_type =3D DMU_OST_ZVOL; else zc.zc_objset_type =3D DMU_OST_ZFS; /* * We rely on zfs_iter_children() to verify that there are no * newer snapshots for the given dataset. Therefore, we can * simply pass the name on to the ioctl() call. There is still * an unlikely race condition where the user has taken a * snapshot since we verified that this was the most recent. * */ if ((err =3D zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_ROLLBACK, &zc)) !=3D 0) { (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno, dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), zhp->zfs_name); return (err); } /* * For volumes, if the pre-rollback volsize matched the pre- * rollback reservation and the volsize has changed then set * the reservation property to the post-rollback volsize. * Make a new handle since the rollback closed the dataset. */ if ((zhp->zfs_type =3D=3D ZFS_TYPE_VOLUME) && (zhp =3D make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) { if (restore_resv) { new_volsize =3D zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); if (old_volsize !=3D new_volsize) err =3D zfs_prop_set_int(zhp, resv_prop, new_volsize); } zfs_close(zhp); } return (err); } /* * Renames the given dataset. */ int zfs_rename(zfs_handle_t *zhp, const char *target, renameflags_t flags) { int ret; zfs_cmd_t zc =3D { 0 }; char *delim; prop_changelist_t *cl =3D NULL; zfs_handle_t *zhrp =3D NULL; char *parentname =3D NULL; char parent[ZFS_MAXNAMELEN]; char property[ZFS_MAXPROPLEN]; libzfs_handle_t *hdl =3D zhp->zfs_hdl; char errbuf[1024]; /* if we have the same exact name, just return success */ if (strcmp(zhp->zfs_name, target) =3D=3D 0) return (0); (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot rename to '%s'"), target); /* * Make sure the target name is valid */ if (zhp->zfs_type =3D=3D ZFS_TYPE_SNAPSHOT) { if ((strchr(target, '@') =3D=3D NULL) || *target =3D=3D '@') { /* * Snapshot target name is abbreviated, * reconstruct full dataset name */ (void) strlcpy(parent, zhp->zfs_name, sizeof (parent)); delim =3D strchr(parent, '@'); if (strchr(target, '@') =3D=3D NULL) *(++delim) =3D '\0'; else *delim =3D '\0'; (void) strlcat(parent, target, sizeof (parent)); target =3D parent; } else { /* * Make sure we're renaming within the same dataset. */ delim =3D strchr(target, '@'); if (strncmp(zhp->zfs_name, target, delim - target) !=3D 0 || zhp->zfs_name[delim - target] !=3D '@') { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "snapshots must be part of same " "dataset")); return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); } } if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); } else { if (flags.recurse) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "recursive rename must be a snapshot")); return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); } if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); /* validate parents */ if (check_parents(hdl, target, NULL, B_FALSE, NULL) !=3D 0) return (-1); /* make sure we're in the same pool */ verify((delim =3D strchr(target, '/')) !=3D NULL); if (strncmp(zhp->zfs_name, target, delim - target) !=3D 0 || zhp->zfs_name[delim - target] !=3D '/') { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "datasets must be within same pool")); return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); } /* new name cannot be a child of the current dataset name */ if (is_descendant(zhp->zfs_name, target)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "New dataset name cannot be a descendant of " "current dataset name")); return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); } } (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); if (getzoneid() =3D=3D GLOBAL_ZONEID && zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "dataset is used in a non-global zone")); return (zfs_error(hdl, EZFS_ZONED, errbuf)); } /* * Avoid unmounting file systems with mountpoint property set to * 'legacy' or 'none' even if -u option is not given. */ if (zhp->zfs_type =3D=3D ZFS_TYPE_FILESYSTEM && !flags.recurse && !flags.nounmount && zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, property, sizeof (property), NULL, NULL, 0, B_FALSE) =3D=3D 0 && (strcmp(property, "legacy") =3D=3D 0 || strcmp(property, "none") =3D=3D 0)) { flags.nounmount =3D B_TRUE; } if (flags.recurse) { parentname =3D zfs_strdup(zhp->zfs_hdl, zhp->zfs_name); if (parentname =3D=3D NULL) { ret =3D -1; goto error; } delim =3D strchr(parentname, '@'); *delim =3D '\0'; zhrp =3D zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_DATASET); if (zhrp =3D=3D NULL) { ret =3D -1; goto error; } } else { if ((cl =3D changelist_gather(zhp, ZFS_PROP_NAME, flags.nounmount ? CL_GATHER_DONT_UNMOUNT : 0, flags.forceunmount ? MS_FORCE : 0)) =3D=3D NULL) { return (-1); } if (changelist_haszonedchild(cl)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "child dataset with inherited mountpoint is used " "in a non-global zone")); (void) zfs_error(hdl, EZFS_ZONED, errbuf); goto error; } if ((ret =3D changelist_prefix(cl)) !=3D 0) goto error; } if (ZFS_IS_VOLUME(zhp)) zc.zc_objset_type =3D DMU_OST_ZVOL; else zc.zc_objset_type =3D DMU_OST_ZFS; (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); zc.zc_cookie =3D flags.recurse ? 1 : 0; if (flags.nounmount) zc.zc_cookie |=3D 2; if ((ret =3D zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) !=3D 0) { /* * if it was recursive, the one that actually failed will * be in zc.zc_name */ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zc.zc_name); if (flags.recurse && errno =3D=3D EEXIST) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "a child dataset already has a snapshot " "with the new name")); (void) zfs_error(hdl, EZFS_EXISTS, errbuf); } else { (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); } /* * On failure, we still want to remount any filesystems that * were previously mounted, so we don't alter the system state. */ if (!flags.recurse) (void) changelist_postfix(cl); } else { if (!flags.recurse) { changelist_rename(cl, zfs_get_name(zhp), target); ret =3D changelist_postfix(cl); } } error: if (parentname) { free(parentname); } if (zhrp) { zfs_close(zhrp); } if (cl) { changelist_free(cl); } return (ret); } nvlist_t * zfs_get_user_props(zfs_handle_t *zhp) { return (zhp->zfs_user_props); } nvlist_t * zfs_get_recvd_props(zfs_handle_t *zhp) { if (zhp->zfs_recvd_props =3D=3D NULL) if (get_recvd_props_ioctl(zhp) !=3D 0) return (NULL); return (zhp->zfs_recvd_props); } /* * This function is used by 'zfs list' to determine the exact set of column= s to * display, and their maximum widths. This does two main things: * * - If this is a list of all properties, then expand the list to incl= ude * all native properties, and set a flag so that for each dataset we= look * for new unique user properties and add them to the list. * * - For non fixed-width properties, keep track of the maximum width s= een * so that we can size the column appropriately. If the user has * requested received property values, we also need to compute the w= idth * of the RECEIVED column. */ int zfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t receiv= ed) { libzfs_handle_t *hdl =3D zhp->zfs_hdl; zprop_list_t *entry; zprop_list_t **last, **start; nvlist_t *userprops, *propval; nvpair_t *elem; char *strval; char buf[ZFS_MAXPROPLEN]; if (zprop_expand_list(hdl, plp, ZFS_TYPE_DATASET) !=3D 0) return (-1); userprops =3D zfs_get_user_props(zhp); entry =3D *plp; if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) !=3D NULL) { /* * Go through and add any user properties as necessary. We * start by incrementing our list pointer to the first * non-native property. */ start =3D plp; while (*start !=3D NULL) { if ((*start)->pl_prop =3D=3D ZPROP_INVAL) break; start =3D &(*start)->pl_next; } elem =3D NULL; while ((elem =3D nvlist_next_nvpair(userprops, elem)) !=3D NULL) { /* * See if we've already found this property in our list. */ for (last =3D start; *last !=3D NULL; last =3D &(*last)->pl_next) { if (strcmp((*last)->pl_user_prop, nvpair_name(elem)) =3D=3D 0) break; } if (*last =3D=3D NULL) { if ((entry =3D zfs_alloc(hdl, sizeof (zprop_list_t))) =3D=3D NULL || ((entry->pl_user_prop =3D zfs_strdup(hdl, nvpair_name(elem)))) =3D=3D NULL) { free(entry); return (-1); } entry->pl_prop =3D ZPROP_INVAL; entry->pl_width =3D strlen(nvpair_name(elem)); entry->pl_all =3D B_TRUE; *last =3D entry; } } } /* * Now go through and check the width of any non-fixed columns */ for (entry =3D *plp; entry !=3D NULL; entry =3D entry->pl_next) { if (entry->pl_fixed) continue; if (entry->pl_prop !=3D ZPROP_INVAL) { if (zfs_prop_get(zhp, entry->pl_prop, buf, sizeof (buf), NULL, NULL, 0, B_FALSE) =3D=3D 0) { if (strlen(buf) > entry->pl_width) entry->pl_width =3D strlen(buf); } if (received && zfs_prop_get_recvd(zhp, zfs_prop_to_name(entry->pl_prop), buf, sizeof (buf), B_FALSE) =3D=3D 0) if (strlen(buf) > entry->pl_recvd_width) entry->pl_recvd_width =3D strlen(buf); } else { if (nvlist_lookup_nvlist(userprops, entry->pl_user_prop, &propval) =3D=3D 0) { verify(nvlist_lookup_string(propval, ZPROP_VALUE, &strval) =3D=3D 0); if (strlen(strval) > entry->pl_width) entry->pl_width =3D strlen(strval); } if (received && zfs_prop_get_recvd(zhp, entry->pl_user_prop, buf, sizeof (buf), B_FALSE) =3D=3D 0) if (strlen(buf) > entry->pl_recvd_width) entry->pl_recvd_width =3D strlen(buf); } } return (0); } int zfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path, char *resource, void *export, void *sharetab, int sharemax, zfs_share_op_t operation) { zfs_cmd_t zc =3D { 0 }; int error; (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); if (resource) (void) strlcpy(zc.zc_string, resource, sizeof (zc.zc_string)); zc.zc_share.z_sharedata =3D (uint64_t)(uintptr_t)sharetab; zc.zc_share.z_exportdata =3D (uint64_t)(uintptr_t)export; zc.zc_share.z_sharetype =3D operation; zc.zc_share.z_sharemax =3D sharemax; error =3D ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc); return (error); } void zfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props) { nvpair_t *curr; /* * Keep a reference to the props-table against which we prune the * properties. */ zhp->zfs_props_table =3D props; curr =3D nvlist_next_nvpair(zhp->zfs_props, NULL); while (curr) { zfs_prop_t zfs_prop =3D zfs_name_to_prop(nvpair_name(curr)); nvpair_t *next =3D nvlist_next_nvpair(zhp->zfs_props, curr); /* * User properties will result in ZPROP_INVAL, and since we * only know how to prune standard ZFS properties, we always * leave these in the list. This can also happen if we * encounter an unknown DSL property (when running older * software, for example). */ if (zfs_prop !=3D ZPROP_INVAL && props[zfs_prop] =3D=3D B_FALSE) (void) nvlist_remove(zhp->zfs_props, nvpair_name(curr), nvpair_type(curr)); curr =3D next; } } #ifdef sun static int zfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path, zfs_smb_acl_op_t cmd, char *resource1, char *resource2) { zfs_cmd_t zc =3D { 0 }; nvlist_t *nvlist =3D NULL; int error; (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); zc.zc_cookie =3D (uint64_t)cmd; if (cmd =3D=3D ZFS_SMB_ACL_RENAME) { if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) !=3D 0) { (void) no_memory(hdl); return (NULL); } } switch (cmd) { case ZFS_SMB_ACL_ADD: case ZFS_SMB_ACL_REMOVE: (void) strlcpy(zc.zc_string, resource1, sizeof (zc.zc_string)); break; case ZFS_SMB_ACL_RENAME: if (nvlist_add_string(nvlist, ZFS_SMB_ACL_SRC, resource1) !=3D 0) { (void) no_memory(hdl); return (-1); } if (nvlist_add_string(nvlist, ZFS_SMB_ACL_TARGET, resource2) !=3D 0) { (void) no_memory(hdl); return (-1); } if (zcmd_write_src_nvlist(hdl, &zc, nvlist) !=3D 0) { nvlist_free(nvlist); return (-1); } break; case ZFS_SMB_ACL_PURGE: break; default: return (-1); } error =3D ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc); if (nvlist) nvlist_free(nvlist); return (error); } int zfs_smb_acl_add(libzfs_handle_t *hdl, char *dataset, char *path, char *resource) { return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_ADD, resource, NULL)); } int zfs_smb_acl_remove(libzfs_handle_t *hdl, char *dataset, char *path, char *resource) { return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_REMOVE, resource, NULL)); } int zfs_smb_acl_purge(libzfs_handle_t *hdl, char *dataset, char *path) { return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_PURGE, NULL, NULL)); } int zfs_smb_acl_rename(libzfs_handle_t *hdl, char *dataset, char *path, char *oldname, char *newname) { return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME, oldname, newname)); } #endif /* sun */ int zfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type, zfs_userspace_cb_t func, void *arg) { zfs_cmd_t zc =3D { 0 }; int error; zfs_useracct_t buf[100]; (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); zc.zc_objset_type =3D type; zc.zc_nvlist_dst =3D (uintptr_t)buf; /* CONSTCOND */ while (1) { zfs_useracct_t *zua =3D buf; zc.zc_nvlist_dst_size =3D sizeof (buf); error =3D ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_MANY, &zc); if (error || zc.zc_nvlist_dst_size =3D=3D 0) break; while (zc.zc_nvlist_dst_size > 0) { error =3D func(arg, zua->zu_domain, zua->zu_rid, zua->zu_space); if (error !=3D 0) return (error); zua++; zc.zc_nvlist_dst_size -=3D sizeof (zfs_useracct_t); } } return (error); } int zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag, boolean_t recursive, boolean_t temphold, boolean_t enoent_ok, int cleanup_fd, uint64_t dsobj, uint64_t createtxg) { zfs_cmd_t zc =3D { 0 }; libzfs_handle_t *hdl =3D zhp->zfs_hdl; ASSERT(!recursive || dsobj =3D=3D 0); (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); if (strlcpy(zc.zc_string, tag, sizeof (zc.zc_string)) >=3D sizeof (zc.zc_string)) return (zfs_error(hdl, EZFS_TAGTOOLONG, tag)); zc.zc_cookie =3D recursive; zc.zc_temphold =3D temphold; zc.zc_cleanup_fd =3D cleanup_fd; zc.zc_sendobj =3D dsobj; zc.zc_createtxg =3D createtxg; if (zfs_ioctl(hdl, ZFS_IOC_HOLD, &zc) !=3D 0) { char errbuf[ZFS_MAXNAMELEN+32]; /* * if it was recursive, the one that actually failed will be in * zc.zc_name. */ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot hold '%s@%s'"), zc.zc_name, snapname); switch (errno) { case E2BIG: /* * Temporary tags wind up having the ds object id * prepended. So even if we passed the length check * above, it's still possible for the tag to wind * up being slightly too long. */ return (zfs_error(hdl, EZFS_TAGTOOLONG, errbuf)); case ENOTSUP: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be upgraded")); return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); case EINVAL: return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); case EEXIST: return (zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf)); case ENOENT: if (enoent_ok) return (ENOENT); /* FALLTHROUGH */ default: return (zfs_standard_error_fmt(hdl, errno, errbuf)); } } return (0); } int zfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag, boolean_t recursive) { zfs_cmd_t zc =3D { 0 }; libzfs_handle_t *hdl =3D zhp->zfs_hdl; (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); if (strlcpy(zc.zc_string, tag, sizeof (zc.zc_string)) >=3D sizeof (zc.zc_string)) return (zfs_error(hdl, EZFS_TAGTOOLONG, tag)); zc.zc_cookie =3D recursive; if (zfs_ioctl(hdl, ZFS_IOC_RELEASE, &zc) !=3D 0) { char errbuf[ZFS_MAXNAMELEN+32]; /* * if it was recursive, the one that actually failed will be in * zc.zc_name. */ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot release '%s' from '%s@%s'"), tag, zc.zc_name, snapname); switch (errno) { case ESRCH: return (zfs_error(hdl, EZFS_REFTAG_RELE, errbuf)); case ENOTSUP: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be upgraded")); return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); case EINVAL: return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); default: return (zfs_standard_error_fmt(hdl, errno, errbuf)); } } return (0); } int zfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl) { zfs_cmd_t zc =3D { 0 }; libzfs_handle_t *hdl =3D zhp->zfs_hdl; int nvsz =3D 2048; void *nvbuf; int err =3D 0; char errbuf[ZFS_MAXNAMELEN+32]; assert(zhp->zfs_type =3D=3D ZFS_TYPE_VOLUME || zhp->zfs_type =3D=3D ZFS_TYPE_FILESYSTEM); tryagain: nvbuf =3D malloc(nvsz); if (nvbuf =3D=3D NULL) { err =3D (zfs_error(hdl, EZFS_NOMEM, strerror(errno))); goto out; } zc.zc_nvlist_dst_size =3D nvsz; zc.zc_nvlist_dst =3D (uintptr_t)nvbuf; (void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN); if (ioctl(hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) !=3D 0) { (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"), zc.zc_name); switch (errno) { case ENOMEM: free(nvbuf); nvsz =3D zc.zc_nvlist_dst_size; goto tryagain; case ENOTSUP: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be upgraded")); err =3D zfs_error(hdl, EZFS_BADVERSION, errbuf); break; case EINVAL: err =3D zfs_error(hdl, EZFS_BADTYPE, errbuf); break; case ENOENT: err =3D zfs_error(hdl, EZFS_NOENT, errbuf); break; default: err =3D zfs_standard_error_fmt(hdl, errno, errbuf); break; } } else { /* success */ int rc =3D nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0); if (rc) { (void) snprintf(errbuf, sizeof (errbuf), dgettext( TEXT_DOMAIN, "cannot get permissions on '%s'"), zc.zc_name); err =3D zfs_standard_error_fmt(hdl, rc, errbuf); } } free(nvbuf); out: return (err); } int zfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl) { zfs_cmd_t zc =3D { 0 }; libzfs_handle_t *hdl =3D zhp->zfs_hdl; char *nvbuf; char errbuf[ZFS_MAXNAMELEN+32]; size_t nvsz; int err; assert(zhp->zfs_type =3D=3D ZFS_TYPE_VOLUME || zhp->zfs_type =3D=3D ZFS_TYPE_FILESYSTEM); err =3D nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE); assert(err =3D=3D 0); nvbuf =3D malloc(nvsz); err =3D nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0); assert(err =3D=3D 0); zc.zc_nvlist_src_size =3D nvsz; zc.zc_nvlist_src =3D (uintptr_t)nvbuf; zc.zc_perm_action =3D un; (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); if (zfs_ioctl(hdl, ZFS_IOC_SET_FSACL, &zc) !=3D 0) { (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot set permissions on '%s'"), zc.zc_name); switch (errno) { case ENOTSUP: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be upgraded")); err =3D zfs_error(hdl, EZFS_BADVERSION, errbuf); break; case EINVAL: err =3D zfs_error(hdl, EZFS_BADTYPE, errbuf); break; case ENOENT: err =3D zfs_error(hdl, EZFS_NOENT, errbuf); break; default: err =3D zfs_standard_error_fmt(hdl, errno, errbuf); break; } } free(nvbuf); return (err); } int zfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl) { zfs_cmd_t zc =3D { 0 }; libzfs_handle_t *hdl =3D zhp->zfs_hdl; int nvsz =3D 2048; void *nvbuf; int err =3D 0; char errbuf[ZFS_MAXNAMELEN+32]; assert(zhp->zfs_type =3D=3D ZFS_TYPE_SNAPSHOT); tryagain: nvbuf =3D malloc(nvsz); if (nvbuf =3D=3D NULL) { err =3D (zfs_error(hdl, EZFS_NOMEM, strerror(errno))); goto out; } zc.zc_nvlist_dst_size =3D nvsz; zc.zc_nvlist_dst =3D (uintptr_t)nvbuf; (void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN); if (zfs_ioctl(hdl, ZFS_IOC_GET_HOLDS, &zc) !=3D 0) { (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"), zc.zc_name); switch (errno) { case ENOMEM: free(nvbuf); nvsz =3D zc.zc_nvlist_dst_size; goto tryagain; case ENOTSUP: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be upgraded")); err =3D zfs_error(hdl, EZFS_BADVERSION, errbuf); break; case EINVAL: err =3D zfs_error(hdl, EZFS_BADTYPE, errbuf); break; case ENOENT: err =3D zfs_error(hdl, EZFS_NOENT, errbuf); break; default: err =3D zfs_standard_error_fmt(hdl, errno, errbuf); break; } } else { /* success */ int rc =3D nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0); if (rc) { (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"), zc.zc_name); err =3D zfs_standard_error_fmt(hdl, rc, errbuf); } } free(nvbuf); out: return (err); } uint64_t zvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props) { uint64_t numdb; uint64_t nblocks, volblocksize; int ncopies; char *strval; if (nvlist_lookup_string(props, zfs_prop_to_name(ZFS_PROP_COPIES), &strval) =3D=3D 0) ncopies =3D atoi(strval); else ncopies =3D 1; if (nvlist_lookup_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), &volblocksize) !=3D 0) volblocksize =3D ZVOL_DEFAULT_BLOCKSIZE; nblocks =3D volsize/volblocksize; /* start with metadnode L0-L6 */ numdb =3D 7; /* calculate number of indirects */ while (nblocks > 1) { nblocks +=3D DNODES_PER_LEVEL - 1; nblocks /=3D DNODES_PER_LEVEL; numdb +=3D nblocks; } numdb *=3D MIN(SPA_DVAS_PER_BP, ncopies + 1); volsize *=3D ncopies; /* * this is exactly DN_MAX_INDBLKSHIFT when metadata isn't * compressed, but in practice they compress down to about * 1100 bytes */ numdb *=3D 1ULL << DN_MAX_INDBLKSHIFT; volsize +=3D numdb; return (volsize); } /* * Attach/detach the given filesystem to/from the given jail. */ int zfs_jail(zfs_handle_t *zhp, int jailid, int attach) { libzfs_handle_t *hdl =3D zhp->zfs_hdl; zfs_cmd_t zc =3D { 0 }; char errbuf[1024]; unsigned long cmd; int ret; if (attach) { (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name); } else { (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name); } switch (zhp->zfs_type) { case ZFS_TYPE_VOLUME: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "volumes can not be jailed")); return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); case ZFS_TYPE_SNAPSHOT: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "snapshots can not be jailed")); return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); } assert(zhp->zfs_type =3D=3D ZFS_TYPE_FILESYSTEM); (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); zc.zc_objset_type =3D DMU_OST_ZFS; zc.zc_jailid =3D jailid; cmd =3D attach ? ZFS_IOC_JAIL : ZFS_IOC_UNJAIL; if ((ret =3D ioctl(hdl->libzfs_fd, cmd, &zc)) !=3D 0) zfs_standard_error(hdl, errno, errbuf); return (ret); } --=-eOAg1opG/d7eXMURa76A Content-Type: text/plain; name="libzfs_dataset.c" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="libzfs_dataset.c" /* * 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) 2005, 2010, Oracle and/or its affiliates. All rights reser= ved. * Copyright 2010 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2011 by Delphix. All rights reserved. * Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved. * Copyright (c) 2011-2012 Pawel Jakub Dawidek . * All rights reserved. * Copyright (c) 2012 Martin Matuska . All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "zfs_namecheck.h" #include "zfs_prop.h" #include "libzfs_impl.h" #include "zfs_deleg.h" static int userquota_propname_decode(const char *propname, boolean_t zoned, zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *rid= p); /* * Given a single type (not a mask of types), return the type in a human * readable form. */ const char * zfs_type_to_name(zfs_type_t type) { switch (type) { case ZFS_TYPE_FILESYSTEM: return (dgettext(TEXT_DOMAIN, "filesystem")); case ZFS_TYPE_SNAPSHOT: return (dgettext(TEXT_DOMAIN, "snapshot")); case ZFS_TYPE_VOLUME: return (dgettext(TEXT_DOMAIN, "volume")); } return (NULL); } /* * Given a path and mask of ZFS types, return a string describing this data= set. * This is used when we fail to open a dataset and we cannot get an exact t= ype. * We guess what the type would have been based on the path and the mask of * acceptable types. */ static const char * path_to_str(const char *path, int types) { /* * When given a single type, always report the exact type. */ if (types =3D=3D ZFS_TYPE_SNAPSHOT) return (dgettext(TEXT_DOMAIN, "snapshot")); if (types =3D=3D ZFS_TYPE_FILESYSTEM) return (dgettext(TEXT_DOMAIN, "filesystem")); if (types =3D=3D ZFS_TYPE_VOLUME) return (dgettext(TEXT_DOMAIN, "volume")); /* * The user is requesting more than one type of dataset. If this is the * case, consult the path itself. If we're looking for a snapshot, and * a '@' is found, then report it as "snapshot". Otherwise, remove the * snapshot attribute and try again. */ if (types & ZFS_TYPE_SNAPSHOT) { if (strchr(path, '@') !=3D NULL) return (dgettext(TEXT_DOMAIN, "snapshot")); return (path_to_str(path, types & ~ZFS_TYPE_SNAPSHOT)); } /* * The user has requested either filesystems or volumes. * We have no way of knowing a priori what type this would be, so always * report it as "filesystem" or "volume", our two primitive types. */ if (types & ZFS_TYPE_FILESYSTEM) return (dgettext(TEXT_DOMAIN, "filesystem")); assert(types & ZFS_TYPE_VOLUME); return (dgettext(TEXT_DOMAIN, "volume")); } /* * Validate a ZFS path. This is used even before trying to open the datase= t, to * provide a more meaningful error message. We call zfs_error_aux() to * explain exactly why the name was not valid. */ int zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type, boolean_t modifying) { namecheck_err_t why; char what; (void) zfs_prop_get_table(); if (dataset_namecheck(path, &why, &what) !=3D 0) { if (hdl !=3D NULL) { switch (why) { case NAME_ERR_TOOLONG: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "name is too long")); break; case NAME_ERR_LEADING_SLASH: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "leading slash in name")); break; case NAME_ERR_EMPTY_COMPONENT: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "empty component in name")); break; case NAME_ERR_TRAILING_SLASH: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "trailing slash in name")); break; case NAME_ERR_INVALCHAR: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid character " "'%c' in name"), what); break; case NAME_ERR_MULTIPLE_AT: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "multiple '@' delimiters in name")); break; case NAME_ERR_NOLETTER: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool doesn't begin with a letter")); break; case NAME_ERR_RESERVED: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "name is reserved")); break; case NAME_ERR_DISKLIKE: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "reserved disk name")); break; } } return (0); } if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') !=3D NULL) { if (hdl !=3D NULL) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "snapshot delimiter '@' in filesystem name")); return (0); } if (type =3D=3D ZFS_TYPE_SNAPSHOT && strchr(path, '@') =3D=3D NULL) { if (hdl !=3D NULL) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "missing '@' delimiter in snapshot name")); return (0); } if (modifying && strchr(path, '%') !=3D NULL) { if (hdl !=3D NULL) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid character %c in name"), '%'); return (0); } return (-1); } int zfs_name_valid(const char *name, zfs_type_t type) { if (type =3D=3D ZFS_TYPE_POOL) return (zpool_name_valid(NULL, B_FALSE, name)); return (zfs_validate_name(NULL, name, type, B_FALSE)); } /* * This function takes the raw DSL properties, and filters out the user-def= ined * properties into a separate nvlist. */ static nvlist_t * process_user_props(zfs_handle_t *zhp, nvlist_t *props) { libzfs_handle_t *hdl =3D zhp->zfs_hdl; nvpair_t *elem; nvlist_t *propval; nvlist_t *nvl; if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) !=3D 0) { (void) no_memory(hdl); return (NULL); } elem =3D NULL; while ((elem =3D nvlist_next_nvpair(props, elem)) !=3D NULL) { if (!zfs_prop_user(nvpair_name(elem))) continue; verify(nvpair_value_nvlist(elem, &propval) =3D=3D 0); if (nvlist_add_nvlist(nvl, nvpair_name(elem), propval) !=3D 0) { nvlist_free(nvl); (void) no_memory(hdl); return (NULL); } } return (nvl); } static zpool_handle_t * zpool_add_handle(zfs_handle_t *zhp, const char *pool_name) { libzfs_handle_t *hdl =3D zhp->zfs_hdl; zpool_handle_t *zph; if ((zph =3D zpool_open_canfail(hdl, pool_name)) !=3D NULL) { if (hdl->libzfs_pool_handles !=3D NULL) zph->zpool_next =3D hdl->libzfs_pool_handles; hdl->libzfs_pool_handles =3D zph; } return (zph); } static zpool_handle_t * zpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len) { libzfs_handle_t *hdl =3D zhp->zfs_hdl; zpool_handle_t *zph =3D hdl->libzfs_pool_handles; while ((zph !=3D NULL) && (strncmp(pool_name, zpool_get_name(zph), len) !=3D 0)) zph =3D zph->zpool_next; return (zph); } /* * Returns a handle to the pool that contains the provided dataset. * If a handle to that pool already exists then that handle is returned. * Otherwise, a new handle is created and added to the list of handles. */ static zpool_handle_t * zpool_handle(zfs_handle_t *zhp) { char *pool_name; int len; zpool_handle_t *zph; len =3D strcspn(zhp->zfs_name, "/@") + 1; pool_name =3D zfs_alloc(zhp->zfs_hdl, len); (void) strlcpy(pool_name, zhp->zfs_name, len); zph =3D zpool_find_handle(zhp, pool_name, len); if (zph =3D=3D NULL) zph =3D zpool_add_handle(zhp, pool_name); free(pool_name); return (zph); } void zpool_free_handles(libzfs_handle_t *hdl) { zpool_handle_t *next, *zph =3D hdl->libzfs_pool_handles; while (zph !=3D NULL) { next =3D zph->zpool_next; zpool_close(zph); zph =3D next; } hdl->libzfs_pool_handles =3D NULL; } /* * Utility function to gather stats (objset and zpl) for the given object. */ static int get_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc) { libzfs_handle_t *hdl =3D zhp->zfs_hdl; (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name)); while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) !=3D 0) { if (errno =3D=3D ENOMEM) { if (zcmd_expand_dst_nvlist(hdl, zc) !=3D 0) { return (-1); } } else { return (-1); } } return (0); } /* * Utility function to get the received properties of the given object. */ static int get_recvd_props_ioctl(zfs_handle_t *zhp) { libzfs_handle_t *hdl =3D zhp->zfs_hdl; nvlist_t *recvdprops; zfs_cmd_t zc =3D { 0 }; int err; if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) !=3D 0) return (-1); (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_RECVD_PROPS, &zc) !=3D 0) { if (errno =3D=3D ENOMEM) { if (zcmd_expand_dst_nvlist(hdl, &zc) !=3D 0) { return (-1); } } else { zcmd_free_nvlists(&zc); return (-1); } } err =3D zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &recvdprops); zcmd_free_nvlists(&zc); if (err !=3D 0) return (-1); nvlist_free(zhp->zfs_recvd_props); zhp->zfs_recvd_props =3D recvdprops; return (0); } static int put_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc) { nvlist_t *allprops, *userprops; zhp->zfs_dmustats =3D zc->zc_objset_stats; /* structure assignment */ if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) !=3D 0) { return (-1); } /* * XXX Why do we store the user props separately, in addition to * storing them in zfs_props? */ if ((userprops =3D process_user_props(zhp, allprops)) =3D=3D NULL) { nvlist_free(allprops); return (-1); } nvlist_free(zhp->zfs_props); nvlist_free(zhp->zfs_user_props); zhp->zfs_props =3D allprops; zhp->zfs_user_props =3D userprops; return (0); } static int get_stats(zfs_handle_t *zhp) { int rc =3D 0; zfs_cmd_t zc =3D { 0 }; if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) !=3D 0) return (-1); if (get_stats_ioctl(zhp, &zc) !=3D 0) rc =3D -1; else if (put_stats_zhdl(zhp, &zc) !=3D 0) rc =3D -1; zcmd_free_nvlists(&zc); return (rc); } /* * Refresh the properties currently stored in the handle. */ void zfs_refresh_properties(zfs_handle_t *zhp) { (void) get_stats(zhp); } /* * Makes a handle from the given dataset name. Used by zfs_open() and * zfs_iter_* to create child handles on the fly. */ static int make_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc) { if (put_stats_zhdl(zhp, zc) !=3D 0) return (-1); /* * We've managed to open the dataset and gather statistics. Determine * the high-level type. */ if (zhp->zfs_dmustats.dds_type =3D=3D DMU_OST_ZVOL) zhp->zfs_head_type =3D ZFS_TYPE_VOLUME; else if (zhp->zfs_dmustats.dds_type =3D=3D DMU_OST_ZFS) zhp->zfs_head_type =3D ZFS_TYPE_FILESYSTEM; else abort(); if (zhp->zfs_dmustats.dds_is_snapshot) zhp->zfs_type =3D ZFS_TYPE_SNAPSHOT; else if (zhp->zfs_dmustats.dds_type =3D=3D DMU_OST_ZVOL) zhp->zfs_type =3D ZFS_TYPE_VOLUME; else if (zhp->zfs_dmustats.dds_type =3D=3D DMU_OST_ZFS) zhp->zfs_type =3D ZFS_TYPE_FILESYSTEM; else abort(); /* we should never see any other types */ if ((zhp->zpool_hdl =3D zpool_handle(zhp)) =3D=3D NULL) return (-1); return (0); } zfs_handle_t * make_dataset_handle(libzfs_handle_t *hdl, const char *path) { zfs_cmd_t zc =3D { 0 }; zfs_handle_t *zhp =3D calloc(sizeof (zfs_handle_t), 1); if (zhp =3D=3D NULL) return (NULL); zhp->zfs_hdl =3D hdl; (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name)); if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) !=3D 0) { free(zhp); return (NULL); } if (get_stats_ioctl(zhp, &zc) =3D=3D -1) { zcmd_free_nvlists(&zc); free(zhp); return (NULL); } if (make_dataset_handle_common(zhp, &zc) =3D=3D -1) { free(zhp); zhp =3D NULL; } zcmd_free_nvlists(&zc); return (zhp); } zfs_handle_t * make_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc) { zfs_handle_t *zhp =3D calloc(sizeof (zfs_handle_t), 1); if (zhp =3D=3D NULL) return (NULL); zhp->zfs_hdl =3D hdl; (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); if (make_dataset_handle_common(zhp, zc) =3D=3D -1) { free(zhp); return (NULL); } return (zhp); } zfs_handle_t * make_dataset_simple_handle_zc(zfs_handle_t *pzhp, zfs_cmd_t *zc) { zfs_handle_t *zhp =3D calloc(sizeof (zfs_handle_t), 1); if (zhp =3D=3D NULL) return (NULL); zhp->zfs_hdl =3D pzhp->zfs_hdl; (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name)); zhp->zfs_head_type =3D pzhp->zfs_type; zhp->zfs_type =3D ZFS_TYPE_SNAPSHOT; zhp->zpool_hdl =3D zpool_handle(zhp); return (zhp); } zfs_handle_t * zfs_handle_dup(zfs_handle_t *zhp_orig) { zfs_handle_t *zhp =3D calloc(sizeof (zfs_handle_t), 1); if (zhp =3D=3D NULL) return (NULL); zhp->zfs_hdl =3D zhp_orig->zfs_hdl; zhp->zpool_hdl =3D zhp_orig->zpool_hdl; (void) strlcpy(zhp->zfs_name, zhp_orig->zfs_name, sizeof (zhp->zfs_name)); zhp->zfs_type =3D zhp_orig->zfs_type; zhp->zfs_head_type =3D zhp_orig->zfs_head_type; zhp->zfs_dmustats =3D zhp_orig->zfs_dmustats; if (zhp_orig->zfs_props !=3D NULL) { if (nvlist_dup(zhp_orig->zfs_props, &zhp->zfs_props, 0) !=3D 0) { (void) no_memory(zhp->zfs_hdl); zfs_close(zhp); return (NULL); } } if (zhp_orig->zfs_user_props !=3D NULL) { if (nvlist_dup(zhp_orig->zfs_user_props, &zhp->zfs_user_props, 0) !=3D 0) { (void) no_memory(zhp->zfs_hdl); zfs_close(zhp); return (NULL); } } if (zhp_orig->zfs_recvd_props !=3D NULL) { if (nvlist_dup(zhp_orig->zfs_recvd_props, &zhp->zfs_recvd_props, 0)) { (void) no_memory(zhp->zfs_hdl); zfs_close(zhp); return (NULL); } } zhp->zfs_mntcheck =3D zhp_orig->zfs_mntcheck; if (zhp_orig->zfs_mntopts !=3D NULL) { zhp->zfs_mntopts =3D zfs_strdup(zhp_orig->zfs_hdl, zhp_orig->zfs_mntopts); } zhp->zfs_props_table =3D zhp_orig->zfs_props_table; return (zhp); } /* * Opens the given snapshot, filesystem, or volume. The 'types' * argument is a mask of acceptable types. The function will print an * appropriate error message and return NULL if it can't be opened. */ zfs_handle_t * zfs_open(libzfs_handle_t *hdl, const char *path, int types) { zfs_handle_t *zhp; char errbuf[1024]; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); /* * Validate the name before we even try to open it. */ if (!zfs_validate_name(hdl, path, ZFS_TYPE_DATASET, B_FALSE)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid dataset name")); (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); return (NULL); } /* * Try to get stats for the dataset, which will tell us if it exists. */ errno =3D 0; if ((zhp =3D make_dataset_handle(hdl, path)) =3D=3D NULL) { (void) zfs_standard_error(hdl, errno, errbuf); return (NULL); } if (!(types & zhp->zfs_type)) { (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); zfs_close(zhp); return (NULL); } return (zhp); } /* * Release a ZFS handle. Nothing to do but free the associated memory. */ void zfs_close(zfs_handle_t *zhp) { if (zhp->zfs_mntopts) free(zhp->zfs_mntopts); nvlist_free(zhp->zfs_props); nvlist_free(zhp->zfs_user_props); nvlist_free(zhp->zfs_recvd_props); free(zhp); } typedef struct mnttab_node { struct mnttab mtn_mt; avl_node_t mtn_node; } mnttab_node_t; static int libzfs_mnttab_cache_compare(const void *arg1, const void *arg2) { const mnttab_node_t *mtn1 =3D arg1; const mnttab_node_t *mtn2 =3D arg2; int rv; rv =3D strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special); if (rv =3D=3D 0) return (0); return (rv > 0 ? 1 : -1); } void libzfs_mnttab_init(libzfs_handle_t *hdl) { assert(avl_numnodes(&hdl->libzfs_mnttab_cache) =3D=3D 0); avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare, sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node)); } void libzfs_mnttab_update(libzfs_handle_t *hdl) { struct mnttab entry; rewind(hdl->libzfs_mnttab); while (getmntent(hdl->libzfs_mnttab, &entry) =3D=3D 0) { mnttab_node_t *mtn; if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) !=3D 0) continue; mtn =3D zfs_alloc(hdl, sizeof (mnttab_node_t)); mtn->mtn_mt.mnt_special =3D zfs_strdup(hdl, entry.mnt_special); mtn->mtn_mt.mnt_mountp =3D zfs_strdup(hdl, entry.mnt_mountp); mtn->mtn_mt.mnt_fstype =3D zfs_strdup(hdl, entry.mnt_fstype); mtn->mtn_mt.mnt_mntopts =3D zfs_strdup(hdl, entry.mnt_mntopts); avl_add(&hdl->libzfs_mnttab_cache, mtn); } } void libzfs_mnttab_fini(libzfs_handle_t *hdl) { void *cookie =3D NULL; mnttab_node_t *mtn; while (mtn =3D avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie)) { free(mtn->mtn_mt.mnt_special); free(mtn->mtn_mt.mnt_mountp); free(mtn->mtn_mt.mnt_fstype); free(mtn->mtn_mt.mnt_mntopts); free(mtn); } avl_destroy(&hdl->libzfs_mnttab_cache); } void libzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable) { hdl->libzfs_mnttab_enable =3D enable; } int libzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname, struct mnttab *entry) { mnttab_node_t find; mnttab_node_t *mtn; if (!hdl->libzfs_mnttab_enable) { struct mnttab srch =3D { 0 }; if (avl_numnodes(&hdl->libzfs_mnttab_cache)) libzfs_mnttab_fini(hdl); rewind(hdl->libzfs_mnttab); srch.mnt_special =3D (char *)fsname; srch.mnt_fstype =3D MNTTYPE_ZFS; if (getmntany(hdl->libzfs_mnttab, entry, &srch) =3D=3D 0) return (0); else return (ENOENT); } if (avl_numnodes(&hdl->libzfs_mnttab_cache) =3D=3D 0) libzfs_mnttab_update(hdl); find.mtn_mt.mnt_special =3D (char *)fsname; mtn =3D avl_find(&hdl->libzfs_mnttab_cache, &find, NULL); if (mtn) { *entry =3D mtn->mtn_mt; return (0); } return (ENOENT); } void libzfs_mnttab_add(libzfs_handle_t *hdl, const char *special, const char *mountp, const char *mntopts) { mnttab_node_t *mtn; if (avl_numnodes(&hdl->libzfs_mnttab_cache) =3D=3D 0) return; mtn =3D zfs_alloc(hdl, sizeof (mnttab_node_t)); mtn->mtn_mt.mnt_special =3D zfs_strdup(hdl, special); mtn->mtn_mt.mnt_mountp =3D zfs_strdup(hdl, mountp); mtn->mtn_mt.mnt_fstype =3D zfs_strdup(hdl, MNTTYPE_ZFS); mtn->mtn_mt.mnt_mntopts =3D zfs_strdup(hdl, mntopts); avl_add(&hdl->libzfs_mnttab_cache, mtn); } void libzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname) { mnttab_node_t find; mnttab_node_t *ret; find.mtn_mt.mnt_special =3D (char *)fsname; if (ret =3D avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL)) { avl_remove(&hdl->libzfs_mnttab_cache, ret); free(ret->mtn_mt.mnt_special); free(ret->mtn_mt.mnt_mountp); free(ret->mtn_mt.mnt_fstype); free(ret->mtn_mt.mnt_mntopts); free(ret); } } int zfs_spa_version(zfs_handle_t *zhp, int *spa_version) { zpool_handle_t *zpool_handle =3D zhp->zpool_hdl; if (zpool_handle =3D=3D NULL) return (-1); *spa_version =3D zpool_get_prop_int(zpool_handle, ZPOOL_PROP_VERSION, NULL); return (0); } /* * The choice of reservation property depends on the SPA version. */ static int zfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop) { int spa_version; if (zfs_spa_version(zhp, &spa_version) < 0) return (-1); if (spa_version >=3D SPA_VERSION_REFRESERVATION) *resv_prop =3D ZFS_PROP_REFRESERVATION; else *resv_prop =3D ZFS_PROP_RESERVATION; return (0); } /* * Given an nvlist of properties to set, validates that they are correct, a= nd * parses any numeric properties (index, boolean, etc) if they are specifie= d as * strings. */ nvlist_t * zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, uint64_t zoned, zfs_handle_t *zhp, const char *errbuf) { nvpair_t *elem; uint64_t intval; char *strval; zfs_prop_t prop; nvlist_t *ret; int chosen_normal =3D -1; int chosen_utf =3D -1; if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) !=3D 0) { (void) no_memory(hdl); return (NULL); } /* * Make sure this property is valid and applies to this type. */ elem =3D NULL; while ((elem =3D nvlist_next_nvpair(nvl, elem)) !=3D NULL) { const char *propname =3D nvpair_name(elem); prop =3D zfs_name_to_prop(propname); if (prop =3D=3D ZPROP_INVAL && zfs_prop_user(propname)) { /* * This is a user property: make sure it's a * string, and that it's less than ZAP_MAXNAMELEN. */ if (nvpair_type(elem) !=3D DATA_TYPE_STRING) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' must be a string"), propname); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } if (strlen(nvpair_name(elem)) >=3D ZAP_MAXNAMELEN) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "property name '%s' is too long"), propname); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } (void) nvpair_value_string(elem, &strval); if (nvlist_add_string(ret, propname, strval) !=3D 0) { (void) no_memory(hdl); goto error; } continue; } /* * Currently, only user properties can be modified on * snapshots. */ if (type =3D=3D ZFS_TYPE_SNAPSHOT) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "this property can not be modified for snapshots")); (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); goto error; } if (prop =3D=3D ZPROP_INVAL && zfs_prop_userquota(propname)) { zfs_userquota_prop_t uqtype; char newpropname[128]; char domain[128]; uint64_t rid; uint64_t valary[3]; if (userquota_propname_decode(propname, zoned, &uqtype, domain, sizeof (domain), &rid) !=3D 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' has an invalid user/group name"), propname); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } if (uqtype !=3D ZFS_PROP_USERQUOTA && uqtype !=3D ZFS_PROP_GROUPQUOTA) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' is readonly"), propname); (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); goto error; } if (nvpair_type(elem) =3D=3D DATA_TYPE_STRING) { (void) nvpair_value_string(elem, &strval); if (strcmp(strval, "none") =3D=3D 0) { intval =3D 0; } else if (zfs_nicestrtonum(hdl, strval, &intval) !=3D 0) { (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } } else if (nvpair_type(elem) =3D=3D DATA_TYPE_UINT64) { (void) nvpair_value_uint64(elem, &intval); if (intval =3D=3D 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "use 'none' to disable " "userquota/groupquota")); goto error; } } else { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' must be a number"), propname); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } /* * Encode the prop name as * userquota@-domain, to make it easy * for the kernel to decode. */ (void) snprintf(newpropname, sizeof (newpropname), "%s%llx-%s", zfs_userquota_prop_prefixes[uqtype], (longlong_t)rid, domain); valary[0] =3D uqtype; valary[1] =3D rid; valary[2] =3D intval; if (nvlist_add_uint64_array(ret, newpropname, valary, 3) !=3D 0) { (void) no_memory(hdl); goto error; } continue; } else if (prop =3D=3D ZPROP_INVAL && zfs_prop_written(propname)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' is readonly"), propname); (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); goto error; } if (prop =3D=3D ZPROP_INVAL) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid property '%s'"), propname); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } if (!zfs_prop_valid_for_type(prop, type)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' does not " "apply to datasets of this type"), propname); (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); goto error; } if (zfs_prop_readonly(prop) && (!zfs_prop_setonce(prop) || zhp !=3D NULL)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' is readonly"), propname); (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf); goto error; } if (zprop_parse_value(hdl, elem, prop, type, ret, &strval, &intval, errbuf) !=3D 0) goto error; /* * Perform some additional checks for specific properties. */ switch (prop) { case ZFS_PROP_VERSION: { int version; if (zhp =3D=3D NULL) break; version =3D zfs_prop_get_int(zhp, ZFS_PROP_VERSION); if (intval < version) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "Can not downgrade; already at version %u"), version); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } break; } case ZFS_PROP_RECORDSIZE: case ZFS_PROP_VOLBLOCKSIZE: /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ if (intval < SPA_MINBLOCKSIZE || intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' must be power of 2 from %u " "to %uk"), propname, (uint_t)SPA_MINBLOCKSIZE, (uint_t)SPA_MAXBLOCKSIZE >> 10); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } break; case ZFS_PROP_MLSLABEL: { #ifdef sun /* * Verify the mlslabel string and convert to * internal hex label string. */ m_label_t *new_sl; char *hex =3D NULL; /* internal label string */ /* Default value is already OK. */ if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) =3D=3D 0) break; /* Verify the label can be converted to binary form */ if (((new_sl =3D m_label_alloc(MAC_LABEL)) =3D=3D NULL) || (str_to_label(strval, &new_sl, MAC_LABEL, L_NO_CORRECTION, NULL) =3D=3D -1)) { goto badlabel; } /* Now translate to hex internal label string */ if (label_to_str(new_sl, &hex, M_INTERNAL, DEF_NAMES) !=3D 0) { if (hex) free(hex); goto badlabel; } m_label_free(new_sl); /* If string is already in internal form, we're done. */ if (strcmp(strval, hex) =3D=3D 0) { free(hex); break; } /* Replace the label string with the internal form. */ (void) nvlist_remove(ret, zfs_prop_to_name(prop), DATA_TYPE_STRING); verify(nvlist_add_string(ret, zfs_prop_to_name(prop), hex) =3D=3D 0); free(hex); break; badlabel: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid mlslabel '%s'"), strval); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); m_label_free(new_sl); /* OK if null */ #else /* !sun */ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "mlslabel is not supported on FreeBSD")); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); #endif /* !sun */ goto error; } case ZFS_PROP_MOUNTPOINT: { namecheck_err_t why; if (strcmp(strval, ZFS_MOUNTPOINT_NONE) =3D=3D 0 || strcmp(strval, ZFS_MOUNTPOINT_LEGACY) =3D=3D 0) break; if (mountpoint_namecheck(strval, &why)) { switch (why) { case NAME_ERR_LEADING_SLASH: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' must be an absolute path, " "'none', or 'legacy'"), propname); break; case NAME_ERR_TOOLONG: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "component of '%s' is too long"), propname); break; } (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } } /*FALLTHRU*/ case ZFS_PROP_SHARESMB: case ZFS_PROP_SHARENFS: /* * For the mountpoint and sharenfs or sharesmb * properties, check if it can be set in a * global/non-global zone based on * the zoned property value: * * global zone non-global zone * -------------------------------------------------- * zoned=3Don mountpoint (no) mountpoint (yes) * sharenfs (no) sharenfs (no) * sharesmb (no) sharesmb (no) * * zoned=3Doff mountpoint (yes) N/A * sharenfs (yes) * sharesmb (yes) */ if (zoned) { if (getzoneid() =3D=3D GLOBAL_ZONEID) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' cannot be set on " "dataset in a non-global zone"), propname); (void) zfs_error(hdl, EZFS_ZONED, errbuf); goto error; } else if (prop =3D=3D ZFS_PROP_SHARENFS || prop =3D=3D ZFS_PROP_SHARESMB) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' cannot be set in " "a non-global zone"), propname); (void) zfs_error(hdl, EZFS_ZONED, errbuf); goto error; } } else if (getzoneid() !=3D GLOBAL_ZONEID) { /* * If zoned property is 'off', this must be in * a global zone. If not, something is wrong. */ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' cannot be set while dataset " "'zoned' property is set"), propname); (void) zfs_error(hdl, EZFS_ZONED, errbuf); goto error; } /* * At this point, it is legitimate to set the * property. Now we want to make sure that the * property value is valid if it is sharenfs. */ if ((prop =3D=3D ZFS_PROP_SHARENFS || prop =3D=3D ZFS_PROP_SHARESMB) && strcmp(strval, "on") !=3D 0 && strcmp(strval, "off") !=3D 0) { zfs_share_proto_t proto; if (prop =3D=3D ZFS_PROP_SHARESMB) proto =3D PROTO_SMB; else proto =3D PROTO_NFS; /* * Must be an valid sharing protocol * option string so init the libshare * in order to enable the parser and * then parse the options. We use the * control API since we don't care about * the current configuration and don't * want the overhead of loading it * until we actually do something. */ if (zfs_init_libshare(hdl, SA_INIT_CONTROL_API) !=3D SA_OK) { /* * An error occurred so we can't do * anything */ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' cannot be set: problem " "in share initialization"), propname); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } if (zfs_parse_options(strval, proto) !=3D SA_OK) { /* * There was an error in parsing so * deal with it by issuing an error * message and leaving after * uninitializing the the libshare * interface. */ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' cannot be set to invalid " "options"), propname); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); zfs_uninit_libshare(hdl); goto error; } zfs_uninit_libshare(hdl); } break; case ZFS_PROP_UTF8ONLY: chosen_utf =3D (int)intval; break; case ZFS_PROP_NORMALIZE: chosen_normal =3D (int)intval; break; } /* * For changes to existing volumes, we have some additional * checks to enforce. */ if (type =3D=3D ZFS_TYPE_VOLUME && zhp !=3D NULL) { uint64_t volsize =3D zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); uint64_t blocksize =3D zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE); char buf[64]; switch (prop) { case ZFS_PROP_RESERVATION: case ZFS_PROP_REFRESERVATION: if (intval > volsize) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' is greater than current " "volume size"), propname); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } break; case ZFS_PROP_VOLSIZE: if (intval % blocksize !=3D 0) { zfs_nicenum(blocksize, buf, sizeof (buf)); zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' must be a multiple of " "volume block size (%s)"), propname, buf); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } if (intval =3D=3D 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' cannot be zero"), propname); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } break; } } } /* * If normalization was chosen, but no UTF8 choice was made, * enforce rejection of non-UTF8 names. * * If normalization was chosen, but rejecting non-UTF8 names * was explicitly not chosen, it is an error. */ if (chosen_normal > 0 && chosen_utf < 0) { if (nvlist_add_uint64(ret, zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) !=3D 0) { (void) no_memory(hdl); goto error; } } else if (chosen_normal > 0 && chosen_utf =3D=3D 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' must be set 'on' if normalization chosen"), zfs_prop_to_name(ZFS_PROP_UTF8ONLY)); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } return (ret); error: nvlist_free(ret); return (NULL); } int zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl) { uint64_t old_volsize; uint64_t new_volsize; uint64_t old_reservation; uint64_t new_reservation; zfs_prop_t resv_prop; /* * If this is an existing volume, and someone is setting the volsize, * make sure that it matches the reservation, or add it if necessary. */ old_volsize =3D zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); if (zfs_which_resv_prop(zhp, &resv_prop) < 0) return (-1); old_reservation =3D zfs_prop_get_int(zhp, resv_prop); if ((zvol_volsize_to_reservation(old_volsize, zhp->zfs_props) !=3D old_reservation) || nvlist_lookup_uint64(nvl, zfs_prop_to_name(resv_prop), &new_reservation) !=3D ENOENT) { return (0); } if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE), &new_volsize) !=3D 0) return (-1); new_reservation =3D zvol_volsize_to_reservation(new_volsize, zhp->zfs_props); if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop), new_reservation) !=3D 0) { (void) no_memory(zhp->zfs_hdl); return (-1); } return (1); } void zfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err, char *errbuf) { switch (err) { case ENOSPC: /* * For quotas and reservations, ENOSPC indicates * something different; setting a quota or reservation * doesn't use any disk space. */ switch (prop) { case ZFS_PROP_QUOTA: case ZFS_PROP_REFQUOTA: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "size is less than current used or " "reserved space")); (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); break; case ZFS_PROP_RESERVATION: case ZFS_PROP_REFRESERVATION: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "size is greater than available space")); (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf); break; default: (void) zfs_standard_error(hdl, err, errbuf); break; } break; case EBUSY: (void) zfs_standard_error(hdl, EBUSY, errbuf); break; case EROFS: (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf); break; case ENOTSUP: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool and or dataset must be upgraded to set this " "property or value")); (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); break; case ERANGE: if (prop =3D=3D ZFS_PROP_COMPRESSION) { (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "property setting is not allowed on " "bootable datasets")); (void) zfs_error(hdl, EZFS_NOTSUP, errbuf); } else { (void) zfs_standard_error(hdl, err, errbuf); } break; case EINVAL: if (prop =3D=3D ZPROP_INVAL) { (void) zfs_error(hdl, EZFS_BADPROP, errbuf); } else { (void) zfs_standard_error(hdl, err, errbuf); } break; case EOVERFLOW: /* * This platform can't address a volume this big. */ #ifdef _ILP32 if (prop =3D=3D ZFS_PROP_VOLSIZE) { (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf); break; } #endif /* FALLTHROUGH */ default: (void) zfs_standard_error(hdl, err, errbuf); } } /* * Given a property name and value, set the property for the given dataset. */ int zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) { zfs_cmd_t zc =3D { 0 }; int ret =3D -1; prop_changelist_t *cl =3D NULL; char errbuf[1024]; libzfs_handle_t *hdl =3D zhp->zfs_hdl; nvlist_t *nvl =3D NULL, *realprops; zfs_prop_t prop; boolean_t do_prefix; uint64_t idx; int added_resv; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), zhp->zfs_name); if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) !=3D 0 || nvlist_add_string(nvl, propname, propval) !=3D 0) { (void) no_memory(hdl); goto error; } if ((realprops =3D zfs_valid_proplist(hdl, zhp->zfs_type, nvl, zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) =3D=3D NULL) goto error; nvlist_free(nvl); nvl =3D realprops; prop =3D zfs_name_to_prop(propname); /* We don't support those properties on FreeBSD. */ switch (prop) { case ZFS_PROP_DEVICES: case ZFS_PROP_ISCSIOPTIONS: case ZFS_PROP_XATTR: case ZFS_PROP_VSCAN: case ZFS_PROP_NBMAND: case ZFS_PROP_MLSLABEL: (void) snprintf(errbuf, sizeof (errbuf), "property '%s' not supported on FreeBSD", propname); ret =3D zfs_error(hdl, EZFS_PERM, errbuf); goto error; } if (prop =3D=3D ZFS_PROP_VOLSIZE) { if ((added_resv =3D zfs_add_synthetic_resv(zhp, nvl)) =3D=3D -1) goto error; } if ((cl =3D changelist_gather(zhp, prop, 0, 0)) =3D=3D NULL) goto error; if (prop =3D=3D ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "child dataset with inherited mountpoint is used " "in a non-global zone")); ret =3D zfs_error(hdl, EZFS_ZONED, errbuf); goto error; } /* * If the dataset's canmount property is being set to noauto, * then we want to prevent unmounting & remounting it. */ do_prefix =3D !((prop =3D=3D ZFS_PROP_CANMOUNT) && (zprop_string_to_index(prop, propval, &idx, ZFS_TYPE_DATASET) =3D=3D 0) && (idx =3D=3D ZFS_CANMOUNT_NOAUTO)); if (do_prefix && (ret =3D changelist_prefix(cl)) !=3D 0) goto error; /* * Execute the corresponding ioctl() to set this property. */ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); if (zcmd_write_src_nvlist(hdl, &zc, nvl) !=3D 0) goto error; ret =3D zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); if (ret !=3D 0) { zfs_setprop_error(hdl, prop, errno, errbuf); if (added_resv && errno =3D=3D ENOSPC) { /* clean up the volsize property we tried to set */ uint64_t old_volsize =3D zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); nvlist_free(nvl); zcmd_free_nvlists(&zc); if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) !=3D 0) goto error; if (nvlist_add_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE), old_volsize) !=3D 0) goto error; if (zcmd_write_src_nvlist(hdl, &zc, nvl) !=3D 0) goto error; (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc); } } else { if (do_prefix) ret =3D changelist_postfix(cl); /* * Refresh the statistics so the new property value * is reflected. */ if (ret =3D=3D 0) (void) get_stats(zhp); } error: nvlist_free(nvl); zcmd_free_nvlists(&zc); if (cl) changelist_free(cl); return (ret); } /* * Given a property, inherit the value from the parent dataset, or if recei= ved * is TRUE, revert to the received value, if any. */ int zfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t receive= d) { zfs_cmd_t zc =3D { 0 }; int ret; prop_changelist_t *cl; libzfs_handle_t *hdl =3D zhp->zfs_hdl; char errbuf[1024]; zfs_prop_t prop; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot inherit %s for '%s'"), propname, zhp->zfs_name); zc.zc_cookie =3D received; if ((prop =3D zfs_name_to_prop(propname)) =3D=3D ZPROP_INVAL) { /* * For user properties, the amount of work we have to do is very * small, so just do it here. */ if (!zfs_prop_user(propname)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid property")); return (zfs_error(hdl, EZFS_BADPROP, errbuf)); } (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) !=3D 0) return (zfs_standard_error(hdl, errno, errbuf)); return (0); } /* * Verify that this property is inheritable. */ if (zfs_prop_readonly(prop)) return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf)); if (!zfs_prop_inheritable(prop) && !received) return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf)); /* * Check to see if the value applies to this type */ if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); /* * Normalize the name, to get rid of shorthand abbreviations. */ propname =3D zfs_prop_to_name(prop); (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value)); if (prop =3D=3D ZFS_PROP_MOUNTPOINT && getzoneid() =3D=3D GLOBAL_ZONEID && zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "dataset is used in a non-global zone")); return (zfs_error(hdl, EZFS_ZONED, errbuf)); } /* * Determine datasets which will be affected by this change, if any. */ if ((cl =3D changelist_gather(zhp, prop, 0, 0)) =3D=3D NULL) return (-1); if (prop =3D=3D ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "child dataset with inherited mountpoint is used " "in a non-global zone")); ret =3D zfs_error(hdl, EZFS_ZONED, errbuf); goto error; } if ((ret =3D changelist_prefix(cl)) !=3D 0) goto error; if ((ret =3D zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) !=3D 0) { return (zfs_standard_error(hdl, errno, errbuf)); } else { if ((ret =3D changelist_postfix(cl)) !=3D 0) goto error; /* * Refresh the statistics so the new property is reflected. */ (void) get_stats(zhp); } error: changelist_free(cl); return (ret); } /* * True DSL properties are stored in an nvlist. The following two function= s * extract them appropriately. */ static uint64_t getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source) { nvlist_t *nv; uint64_t value; *source =3D NULL; if (nvlist_lookup_nvlist(zhp->zfs_props, zfs_prop_to_name(prop), &nv) =3D=3D 0) { verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) =3D=3D 0); (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); } else { verify(!zhp->zfs_props_table || zhp->zfs_props_table[prop] =3D=3D B_TRUE); value =3D zfs_prop_default_numeric(prop); *source =3D ""; } return (value); } static char * getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) { nvlist_t *nv; char *value; *source =3D NULL; if (nvlist_lookup_nvlist(zhp->zfs_props, zfs_prop_to_name(prop), &nv) =3D=3D 0) { verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) =3D=3D 0); (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); } else { verify(!zhp->zfs_props_table || zhp->zfs_props_table[prop] =3D=3D B_TRUE); if ((value =3D (char *)zfs_prop_default_string(prop)) =3D=3D NULL) value =3D ""; *source =3D ""; } return (value); } static boolean_t zfs_is_recvd_props_mode(zfs_handle_t *zhp) { return (zhp->zfs_props =3D=3D zhp->zfs_recvd_props); } static void zfs_set_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) { *cookie =3D (uint64_t)(uintptr_t)zhp->zfs_props; zhp->zfs_props =3D zhp->zfs_recvd_props; } static void zfs_unset_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) { zhp->zfs_props =3D (nvlist_t *)(uintptr_t)*cookie; *cookie =3D 0; } /* * Internal function for getting a numeric property. Both zfs_prop_get() a= nd * zfs_prop_get_int() are built using this interface. * * Certain properties can be overridden using 'mount -o'. In this case, sc= an * the contents of the /etc/mnttab entry, searching for the appropriate opt= ions. * If they differ from the on-disk values, report the current values and ma= rk * the source "temporary". */ static int get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *sr= c, char **source, uint64_t *val) { zfs_cmd_t zc =3D { 0 }; nvlist_t *zplprops =3D NULL; struct mnttab mnt; char *mntopt_on =3D NULL; char *mntopt_off =3D NULL; boolean_t received =3D zfs_is_recvd_props_mode(zhp); *source =3D NULL; switch (prop) { case ZFS_PROP_ATIME: mntopt_on =3D MNTOPT_ATIME; mntopt_off =3D MNTOPT_NOATIME; break; case ZFS_PROP_DEVICES: mntopt_on =3D MNTOPT_DEVICES; mntopt_off =3D MNTOPT_NODEVICES; break; case ZFS_PROP_EXEC: mntopt_on =3D MNTOPT_EXEC; mntopt_off =3D MNTOPT_NOEXEC; break; case ZFS_PROP_READONLY: mntopt_on =3D MNTOPT_RO; mntopt_off =3D MNTOPT_RW; break; case ZFS_PROP_SETUID: mntopt_on =3D MNTOPT_SETUID; mntopt_off =3D MNTOPT_NOSETUID; break; case ZFS_PROP_XATTR: mntopt_on =3D MNTOPT_XATTR; mntopt_off =3D MNTOPT_NOXATTR; break; case ZFS_PROP_NBMAND: mntopt_on =3D MNTOPT_NBMAND; mntopt_off =3D MNTOPT_NONBMAND; break; } /* * Because looking up the mount options is potentially expensive * (iterating over all of /etc/mnttab), we defer its calculation until * we're looking up a property which requires its presence. */ if (!zhp->zfs_mntcheck && (mntopt_on !=3D NULL || prop =3D=3D ZFS_PROP_MOUNTED)) { libzfs_handle_t *hdl =3D zhp->zfs_hdl; struct mnttab entry; if (libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) =3D=3D 0) { zhp->zfs_mntopts =3D zfs_strdup(hdl, entry.mnt_mntopts); if (zhp->zfs_mntopts =3D=3D NULL) return (-1); } zhp->zfs_mntcheck =3D B_TRUE; } if (zhp->zfs_mntopts =3D=3D NULL) mnt.mnt_mntopts =3D ""; else mnt.mnt_mntopts =3D zhp->zfs_mntopts; switch (prop) { case ZFS_PROP_ATIME: case ZFS_PROP_DEVICES: case ZFS_PROP_EXEC: case ZFS_PROP_READONLY: case ZFS_PROP_SETUID: case ZFS_PROP_XATTR: case ZFS_PROP_NBMAND: *val =3D getprop_uint64(zhp, prop, source); if (received) break; if (hasmntopt(&mnt, mntopt_on) && !*val) { *val =3D B_TRUE; if (src) *src =3D ZPROP_SRC_TEMPORARY; } else if (hasmntopt(&mnt, mntopt_off) && *val) { *val =3D B_FALSE; if (src) *src =3D ZPROP_SRC_TEMPORARY; } break; case ZFS_PROP_CANMOUNT: case ZFS_PROP_VOLSIZE: case ZFS_PROP_QUOTA: case ZFS_PROP_REFQUOTA: case ZFS_PROP_RESERVATION: case ZFS_PROP_REFRESERVATION: *val =3D getprop_uint64(zhp, prop, source); if (*source =3D=3D NULL) { /* not default, must be local */ *source =3D zhp->zfs_name; } break; case ZFS_PROP_MOUNTED: *val =3D (zhp->zfs_mntopts !=3D NULL); break; case ZFS_PROP_NUMCLONES: *val =3D zhp->zfs_dmustats.dds_num_clones; break; case ZFS_PROP_VERSION: case ZFS_PROP_NORMALIZE: case ZFS_PROP_UTF8ONLY: case ZFS_PROP_CASE: if (!zfs_prop_valid_for_type(prop, zhp->zfs_head_type) || zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) !=3D 0) return (-1); (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) { zcmd_free_nvlists(&zc); return (-1); } if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) !=3D 0 || nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop), val) !=3D 0) { zcmd_free_nvlists(&zc); return (-1); } if (zplprops) nvlist_free(zplprops); zcmd_free_nvlists(&zc); break; default: switch (zfs_prop_get_type(prop)) { case PROP_TYPE_NUMBER: case PROP_TYPE_INDEX: *val =3D getprop_uint64(zhp, prop, source); /* * If we tried to use a default value for a * readonly property, it means that it was not * present. */ if (zfs_prop_readonly(prop) && *source !=3D NULL && (*source)[0] =3D=3D '\0') { *source =3D NULL; } break; case PROP_TYPE_STRING: default: zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, "cannot get non-numeric property")); return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN, "internal error"))); } } return (0); } /* * Calculate the source type, given the raw source string. */ static void get_source(zfs_handle_t *zhp, zprop_source_t *srctype, char *source, char *statbuf, size_t statlen) { if (statbuf =3D=3D NULL || *srctype =3D=3D ZPROP_SRC_TEMPORARY) return; if (source =3D=3D NULL) { *srctype =3D ZPROP_SRC_NONE; } else if (source[0] =3D=3D '\0') { *srctype =3D ZPROP_SRC_DEFAULT; } else if (strstr(source, ZPROP_SOURCE_VAL_RECVD) !=3D NULL) { *srctype =3D ZPROP_SRC_RECEIVED; } else { if (strcmp(source, zhp->zfs_name) =3D=3D 0) { *srctype =3D ZPROP_SRC_LOCAL; } else { (void) strlcpy(statbuf, source, statlen); *srctype =3D ZPROP_SRC_INHERITED; } } } int zfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf, size_t proplen, boolean_t literal) { zfs_prop_t prop; int err =3D 0; if (zhp->zfs_recvd_props =3D=3D NULL) if (get_recvd_props_ioctl(zhp) !=3D 0) return (-1); prop =3D zfs_name_to_prop(propname); if (prop !=3D ZPROP_INVAL) { uint64_t cookie; if (!nvlist_exists(zhp->zfs_recvd_props, propname)) return (-1); zfs_set_recvd_props_mode(zhp, &cookie); err =3D zfs_prop_get(zhp, prop, propbuf, proplen, NULL, NULL, 0, literal); zfs_unset_recvd_props_mode(zhp, &cookie); } else { nvlist_t *propval; char *recvdval; if (nvlist_lookup_nvlist(zhp->zfs_recvd_props, propname, &propval) !=3D 0) return (-1); verify(nvlist_lookup_string(propval, ZPROP_VALUE, &recvdval) =3D=3D 0); (void) strlcpy(propbuf, recvdval, proplen); } return (err =3D=3D 0 ? 0 : -1); } static int get_clones_string(zfs_handle_t *zhp, char *propbuf, size_t proplen) { nvlist_t *value; nvpair_t *pair; value =3D zfs_get_clones_nvl(zhp); if (value =3D=3D NULL) return (-1); propbuf[0] =3D '\0'; for (pair =3D nvlist_next_nvpair(value, NULL); pair !=3D NULL; pair =3D nvlist_next_nvpair(value, pair)) { if (propbuf[0] !=3D '\0') (void) strlcat(propbuf, ",", proplen); (void) strlcat(propbuf, nvpair_name(pair), proplen); } return (0); } struct get_clones_arg { uint64_t numclones; nvlist_t *value; const char *origin; char buf[ZFS_MAXNAMELEN]; }; int get_clones_cb(zfs_handle_t *zhp, void *arg) { struct get_clones_arg *gca =3D arg; if (gca->numclones =3D=3D 0) { zfs_close(zhp); return (0); } if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, gca->buf, sizeof (gca->buf), NULL, NULL, 0, B_TRUE) !=3D 0) goto out; if (strcmp(gca->buf, gca->origin) =3D=3D 0) { if (nvlist_add_boolean(gca->value, zfs_get_name(zhp)) !=3D 0) { zfs_close(zhp); return (no_memory(zhp->zfs_hdl)); } gca->numclones--; } out: (void) zfs_iter_children(zhp, get_clones_cb, gca); zfs_close(zhp); return (0); } nvlist_t * zfs_get_clones_nvl(zfs_handle_t *zhp) { nvlist_t *nv, *value; if (nvlist_lookup_nvlist(zhp->zfs_props, zfs_prop_to_name(ZFS_PROP_CLONES), &nv) !=3D 0) { struct get_clones_arg gca; /* * if this is a snapshot, then the kernel wasn't able * to get the clones. Do it by slowly iterating. */ if (zhp->zfs_type !=3D ZFS_TYPE_SNAPSHOT) return (NULL); if (nvlist_alloc(&nv, NV_UNIQUE_NAME, 0) !=3D 0) return (NULL); if (nvlist_alloc(&value, NV_UNIQUE_NAME, 0) !=3D 0) { nvlist_free(nv); return (NULL); } gca.numclones =3D zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES); gca.value =3D value; gca.origin =3D zhp->zfs_name; if (gca.numclones !=3D 0) { zfs_handle_t *root; char pool[ZFS_MAXNAMELEN]; char *cp =3D pool; /* get the pool name */ (void) strlcpy(pool, zhp->zfs_name, sizeof (pool)); (void) strsep(&cp, "/@"); root =3D zfs_open(zhp->zfs_hdl, pool, ZFS_TYPE_FILESYSTEM); (void) get_clones_cb(root, &gca); } if (gca.numclones !=3D 0 || nvlist_add_nvlist(nv, ZPROP_VALUE, value) !=3D 0 || nvlist_add_nvlist(zhp->zfs_props, zfs_prop_to_name(ZFS_PROP_CLONES), nv) !=3D 0) { nvlist_free(nv); nvlist_free(value); return (NULL); } nvlist_free(nv); nvlist_free(value); verify(0 =3D=3D nvlist_lookup_nvlist(zhp->zfs_props, zfs_prop_to_name(ZFS_PROP_CLONES), &nv)); } verify(nvlist_lookup_nvlist(nv, ZPROP_VALUE, &value) =3D=3D 0); return (value); } /* * Retrieve a property from the given object. If 'literal' is specified, t= hen * numbers are left as exact values. Otherwise, numbers are converted to a * human-readable form. * * Returns 0 on success, or -1 on error. */ int zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t prop= len, zprop_source_t *src, char *statbuf, size_t statlen, boolean_t literal) { char *source =3D NULL; uint64_t val; char *str; const char *strval; boolean_t received =3D zfs_is_recvd_props_mode(zhp); /* * Check to see if this property applies to our object */ if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) return (-1); if (received && zfs_prop_readonly(prop)) return (-1); if (src) *src =3D ZPROP_SRC_NONE; switch (prop) { case ZFS_PROP_CREATION: /* * 'creation' is a time_t stored in the statistics. We convert * this into a string unless 'literal' is specified. */ { val =3D getprop_uint64(zhp, prop, &source); time_t time =3D (time_t)val; struct tm t; if (literal || localtime_r(&time, &t) =3D=3D NULL || strftime(propbuf, proplen, "%a %b %e %k:%M %Y", &t) =3D=3D 0) (void) snprintf(propbuf, proplen, "%llu", val); } break; case ZFS_PROP_MOUNTPOINT: /* * Getting the precise mountpoint can be tricky. * * - for 'none' or 'legacy', return those values. * - for inherited mountpoints, we want to take everything * after our ancestor and append it to the inherited value. * * If the pool has an alternate root, we want to prepend that * root to any values we return. */ str =3D getprop_string(zhp, prop, &source); if (str[0] =3D=3D '/') { char buf[MAXPATHLEN]; char *root =3D buf; const char *relpath; /* * If we inherit the mountpoint, even from a dataset * with a received value, the source will be the path of * the dataset we inherit from. If source is * ZPROP_SOURCE_VAL_RECVD, the received value is not * inherited. */ if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) =3D=3D 0) { relpath =3D ""; } else { relpath =3D zhp->zfs_name + strlen(source); if (relpath[0] =3D=3D '/') relpath++; } if ((zpool_get_prop(zhp->zpool_hdl, ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL)) || (strcmp(root, "-") =3D=3D 0)) root[0] =3D '\0'; /* * Special case an alternate root of '/'. This will * avoid having multiple leading slashes in the * mountpoint path. */ if (strcmp(root, "/") =3D=3D 0) root++; /* * If the mountpoint is '/' then skip over this * if we are obtaining either an alternate root or * an inherited mountpoint. */ if (str[1] =3D=3D '\0' && (root[0] !=3D '\0' || relpath[0] !=3D '\0')) str++; if (relpath[0] =3D=3D '\0') (void) snprintf(propbuf, proplen, "%s%s", root, str); else (void) snprintf(propbuf, proplen, "%s%s%s%s", root, str, relpath[0] =3D=3D '@' ? "" : "/", relpath); } else { /* 'legacy' or 'none' */ (void) strlcpy(propbuf, str, proplen); } break; case ZFS_PROP_ORIGIN: (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), proplen); /* * If there is no parent at all, return failure to indicate that * it doesn't apply to this dataset. */ if (propbuf[0] =3D=3D '\0') return (-1); break; case ZFS_PROP_CLONES: if (get_clones_string(zhp, propbuf, proplen) !=3D 0) return (-1); break; case ZFS_PROP_QUOTA: case ZFS_PROP_REFQUOTA: case ZFS_PROP_RESERVATION: case ZFS_PROP_REFRESERVATION: if (get_numeric_property(zhp, prop, src, &source, &val) !=3D 0) return (-1); /* * If quota or reservation is 0, we translate this into 'none' * (unless literal is set), and indicate that it's the default * value. Otherwise, we print the number nicely and indicate * that its set locally. */ if (val =3D=3D 0) { if (literal) (void) strlcpy(propbuf, "0", proplen); else (void) strlcpy(propbuf, "none", proplen); } else { if (literal) (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val); else zfs_nicenum(val, propbuf, proplen); } break; case ZFS_PROP_REFRATIO: case ZFS_PROP_COMPRESSRATIO: if (get_numeric_property(zhp, prop, src, &source, &val) !=3D 0) return (-1); (void) snprintf(propbuf, proplen, "%llu.%02llux", (u_longlong_t)(val / 100), (u_longlong_t)(val % 100)); break; case ZFS_PROP_TYPE: switch (zhp->zfs_type) { case ZFS_TYPE_FILESYSTEM: str =3D "filesystem"; break; case ZFS_TYPE_VOLUME: str =3D "volume"; break; case ZFS_TYPE_SNAPSHOT: str =3D "snapshot"; break; default: abort(); } (void) snprintf(propbuf, proplen, "%s", str); break; case ZFS_PROP_MOUNTED: /* * The 'mounted' property is a pseudo-property that described * whether the filesystem is currently mounted. Even though * it's a boolean value, the typical values of "on" and "off" * don't make sense, so we translate to "yes" and "no". */ if (get_numeric_property(zhp, ZFS_PROP_MOUNTED, src, &source, &val) !=3D 0) return (-1); if (val) (void) strlcpy(propbuf, "yes", proplen); else (void) strlcpy(propbuf, "no", proplen); break; case ZFS_PROP_NAME: /* * The 'name' property is a pseudo-property derived from the * dataset name. It is presented as a real property to simplify * consumers. */ (void) strlcpy(propbuf, zhp->zfs_name, proplen); break; case ZFS_PROP_MLSLABEL: { #ifdef sun m_label_t *new_sl =3D NULL; char *ascii =3D NULL; /* human readable label */ (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), proplen); if (literal || (strcasecmp(propbuf, ZFS_MLSLABEL_DEFAULT) =3D=3D 0)) break; /* * Try to translate the internal hex string to * human-readable output. If there are any * problems just use the hex string. */ if (str_to_label(propbuf, &new_sl, MAC_LABEL, L_NO_CORRECTION, NULL) =3D=3D -1) { m_label_free(new_sl); break; } if (label_to_str(new_sl, &ascii, M_LABEL, DEF_NAMES) !=3D 0) { if (ascii) free(ascii); m_label_free(new_sl); break; } m_label_free(new_sl); (void) strlcpy(propbuf, ascii, proplen); free(ascii); #else /* !sun */ propbuf[0] =3D '\0'; #endif /* !sun */ } break; case ZFS_PROP_GUID: /* * GUIDs are stored as numbers, but they are identifiers. * We don't want them to be pretty printed, because pretty * printing mangles the ID into a truncated and useless value. */ if (get_numeric_property(zhp, prop, src, &source, &val) !=3D 0) return (-1); (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val); break; default: switch (zfs_prop_get_type(prop)) { case PROP_TYPE_NUMBER: if (get_numeric_property(zhp, prop, src, &source, &val) !=3D 0) return (-1); if (literal) (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val); else zfs_nicenum(val, propbuf, proplen); break; case PROP_TYPE_STRING: (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), proplen); break; case PROP_TYPE_INDEX: if (get_numeric_property(zhp, prop, src, &source, &val) !=3D 0) return (-1); if (zfs_prop_index_to_string(prop, val, &strval) !=3D 0) return (-1); (void) strlcpy(propbuf, strval, proplen); break; default: abort(); } } get_source(zhp, src, source, statbuf, statlen); return (0); } /* * Utility function to get the given numeric property. Does no validation = that * the given property is the appropriate type; should only be used with * hard-coded property types. */ uint64_t zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop) { char *source; uint64_t val; (void) get_numeric_property(zhp, prop, NULL, &source, &val); return (val); } int zfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val) { char buf[64]; (void) snprintf(buf, sizeof (buf), "%llu", (longlong_t)val); return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf)); } /* * Similar to zfs_prop_get(), but returns the value as an integer. */ int zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, zprop_source_t *src, char *statbuf, size_t statlen) { char *source; /* * Check to see if this property applies to our object */ if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) { return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE, dgettext(TEXT_DOMAIN, "cannot get property '%s'"), zfs_prop_to_name(prop))); } if (src) *src =3D ZPROP_SRC_NONE; if (get_numeric_property(zhp, prop, src, &source, value) !=3D 0) return (-1); get_source(zhp, src, source, statbuf, statlen); return (0); } static int idmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser, char **domainp, idmap_rid_t *ridp) { #ifdef sun idmap_get_handle_t *get_hdl =3D NULL; idmap_stat status; int err =3D EINVAL; if (idmap_get_create(&get_hdl) !=3D IDMAP_SUCCESS) goto out; if (isuser) { err =3D idmap_get_sidbyuid(get_hdl, id, IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); } else { err =3D idmap_get_sidbygid(get_hdl, id, IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status); } if (err =3D=3D IDMAP_SUCCESS && idmap_get_mappings(get_hdl) =3D=3D IDMAP_SUCCESS && status =3D=3D IDMAP_SUCCESS) err =3D 0; else err =3D EINVAL; out: if (get_hdl) idmap_get_destroy(get_hdl); return (err); #else /* !sun */ assert(!"invalid code path"); #endif /* !sun */ } /* * convert the propname into parameters needed by kernel * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829 * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789 */ static int userquota_propname_decode(const char *propname, boolean_t zoned, zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *rid= p) { zfs_userquota_prop_t type; char *cp, *end; char *numericsid =3D NULL; boolean_t isuser; domain[0] =3D '\0'; /* Figure out the property type ({user|group}{quota|space}) */ for (type =3D 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) { if (strncmp(propname, zfs_userquota_prop_prefixes[type], strlen(zfs_userquota_prop_prefixes[type])) =3D=3D 0) break; } if (type =3D=3D ZFS_NUM_USERQUOTA_PROPS) return (EINVAL); *typep =3D type; isuser =3D (type =3D=3D ZFS_PROP_USERQUOTA || type =3D=3D ZFS_PROP_USERUSED); cp =3D strchr(propname, '@') + 1; if (strchr(cp, '@')) { #ifdef sun /* * It's a SID name (eg "user@domain") that needs to be * turned into S-1-domainID-RID. */ directory_error_t e; if (zoned && getzoneid() =3D=3D GLOBAL_ZONEID) return (ENOENT); if (isuser) { e =3D directory_sid_from_user_name(NULL, cp, &numericsid); } else { e =3D directory_sid_from_group_name(NULL, cp, &numericsid); } if (e !=3D NULL) { directory_error_free(e); return (ENOENT); } if (numericsid =3D=3D NULL) return (ENOENT); cp =3D numericsid; /* will be further decoded below */ #else /* !sun */ return (ENOENT); #endif /* !sun */ } if (strncmp(cp, "S-1-", 4) =3D=3D 0) { /* It's a numeric SID (eg "S-1-234-567-89") */ (void) strlcpy(domain, cp, domainlen); cp =3D strrchr(domain, '-'); *cp =3D '\0'; cp++; errno =3D 0; *ridp =3D strtoull(cp, &end, 10); if (numericsid) { free(numericsid); numericsid =3D NULL; } if (errno !=3D 0 || *end !=3D '\0') return (EINVAL); } else if (!isdigit(*cp)) { /* * It's a user/group name (eg "user") that needs to be * turned into a uid/gid */ if (zoned && getzoneid() =3D=3D GLOBAL_ZONEID) return (ENOENT); if (isuser) { struct passwd *pw; pw =3D getpwnam(cp); if (pw =3D=3D NULL) return (ENOENT); *ridp =3D pw->pw_uid; } else { struct group *gr; gr =3D getgrnam(cp); if (gr =3D=3D NULL) return (ENOENT); *ridp =3D gr->gr_gid; } } else { /* It's a user/group ID (eg "12345"). */ uid_t id =3D strtoul(cp, &end, 10); idmap_rid_t rid; char *mapdomain; if (*end !=3D '\0') return (EINVAL); if (id > MAXUID) { /* It's an ephemeral ID. */ if (idmap_id_to_numeric_domain_rid(id, isuser, &mapdomain, &rid) !=3D 0) return (ENOENT); (void) strlcpy(domain, mapdomain, domainlen); *ridp =3D rid; } else { *ridp =3D id; } } ASSERT3P(numericsid, =3D=3D, NULL); return (0); } static int zfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname, uint64_t *propvalue, zfs_userquota_prop_t *typep) { int err; zfs_cmd_t zc =3D { 0 }; (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); err =3D userquota_propname_decode(propname, zfs_prop_get_int(zhp, ZFS_PROP_ZONED), typep, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid); zc.zc_objset_type =3D *typep; if (err) return (err); err =3D ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_ONE, &zc); if (err) return (err); *propvalue =3D zc.zc_cookie; return (0); } int zfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname, uint64_t *propvalue) { zfs_userquota_prop_t type; return (zfs_prop_get_userquota_common(zhp, propname, propvalue, &type)); } int zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname, char *propbuf, int proplen, boolean_t literal) { int err; uint64_t propvalue; zfs_userquota_prop_t type; err =3D zfs_prop_get_userquota_common(zhp, propname, &propvalue, &type); if (err) return (err); if (literal) { (void) snprintf(propbuf, proplen, "%llu", propvalue); } else if (propvalue =3D=3D 0 && (type =3D=3D ZFS_PROP_USERQUOTA || type =3D=3D ZFS_PROP_GROUPQUOTA)) { (void) strlcpy(propbuf, "none", proplen); } else { zfs_nicenum(propvalue, propbuf, proplen); } return (0); } int zfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname, uint64_t *propvalue) { int err; zfs_cmd_t zc =3D { 0 }; const char *snapname; (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); snapname =3D strchr(propname, '@') + 1; if (strchr(snapname, '@')) { (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); } else { /* snapname is the short name, append it to zhp's fsname */ char *cp; (void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value)); cp =3D strchr(zc.zc_value, '@'); if (cp !=3D NULL) *cp =3D '\0'; (void) strlcat(zc.zc_value, "@", sizeof (zc.zc_value)); (void) strlcat(zc.zc_value, snapname, sizeof (zc.zc_value)); } err =3D ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_WRITTEN, &zc); if (err) return (err); *propvalue =3D zc.zc_cookie; return (0); } int zfs_prop_get_written(zfs_handle_t *zhp, const char *propname, char *propbuf, int proplen, boolean_t literal) { int err; uint64_t propvalue; err =3D zfs_prop_get_written_int(zhp, propname, &propvalue); if (err) return (err); if (literal) { (void) snprintf(propbuf, proplen, "%llu", propvalue); } else { zfs_nicenum(propvalue, propbuf, proplen); } return (0); } int zfs_get_snapused_int(zfs_handle_t *firstsnap, zfs_handle_t *lastsnap, uint64_t *usedp) { int err; zfs_cmd_t zc =3D { 0 }; (void) strlcpy(zc.zc_name, lastsnap->zfs_name, sizeof (zc.zc_name)); (void) strlcpy(zc.zc_value, firstsnap->zfs_name, sizeof (zc.zc_value)); err =3D ioctl(lastsnap->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_SNAPS, &zc); if (err) return (err); *usedp =3D zc.zc_cookie; return (0); } /* * Returns the name of the given zfs handle. */ const char * zfs_get_name(const zfs_handle_t *zhp) { return (zhp->zfs_name); } /* * Returns the type of the given zfs handle. */ zfs_type_t zfs_get_type(const zfs_handle_t *zhp) { return (zhp->zfs_type); } /* * Is one dataset name a child dataset of another? * * Needs to handle these cases: * Dataset 1 "a/foo" "a/foo" "a/foo" "a/foo" * Dataset 2 "a/fo" "a/foobar" "a/bar/baz" "a/foo/bar" * Descendant? No. No. No. Yes. */ static boolean_t is_descendant(const char *ds1, const char *ds2) { size_t d1len =3D strlen(ds1); /* ds2 can't be a descendant if it's smaller */ if (strlen(ds2) < d1len) return (B_FALSE); /* otherwise, compare strings and verify that there's a '/' char */ return (ds2[d1len] =3D=3D '/' && (strncmp(ds1, ds2, d1len) =3D=3D 0)); } /* * Given a complete name, return just the portion that refers to the parent= . * Will return -1 if there is no parent (path is just the name of the * pool). */ static int parent_name(const char *path, char *buf, size_t buflen) { char *slashp; (void) strlcpy(buf, path, buflen); if ((slashp =3D strrchr(buf, '/')) =3D=3D NULL) return (-1); *slashp =3D '\0'; return (0); } /* * If accept_ancestor is false, then check to make sure that the given path= has * a parent, and that it exists. If accept_ancestor is true, then find the * closest existing ancestor for the given path. In prefixlen return the * length of already existing prefix of the given path. We also fetch the * 'zoned' property, which is used to validate property settings when creat= ing * new datasets. */ static int check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned, boolean_t accept_ancestor, int *prefixlen) { zfs_cmd_t zc =3D { 0 }; char parent[ZFS_MAXNAMELEN]; char *slash; zfs_handle_t *zhp; char errbuf[1024]; uint64_t is_zoned; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot create '%s'"), path); /* get parent, and check to see if this is just a pool */ if (parent_name(path, parent, sizeof (parent)) !=3D 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "missing dataset name")); return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); } /* check to see if the pool exists */ if ((slash =3D strchr(parent, '/')) =3D=3D NULL) slash =3D parent + strlen(parent); (void) strncpy(zc.zc_name, parent, slash - parent); zc.zc_name[slash - parent] =3D '\0'; if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) !=3D 0 && errno =3D=3D ENOENT) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool '%s'"), zc.zc_name); return (zfs_error(hdl, EZFS_NOENT, errbuf)); } /* check to see if the parent dataset exists */ while ((zhp =3D make_dataset_handle(hdl, parent)) =3D=3D NULL) { if (errno =3D=3D ENOENT && accept_ancestor) { /* * Go deeper to find an ancestor, give up on top level. */ if (parent_name(parent, parent, sizeof (parent)) !=3D 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool '%s'"), zc.zc_name); return (zfs_error(hdl, EZFS_NOENT, errbuf)); } } else if (errno =3D=3D ENOENT) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "parent does not exist")); return (zfs_error(hdl, EZFS_NOENT, errbuf)); } else return (zfs_standard_error(hdl, errno, errbuf)); } is_zoned =3D zfs_prop_get_int(zhp, ZFS_PROP_ZONED); if (zoned !=3D NULL) *zoned =3D is_zoned; /* we are in a non-global zone, but parent is in the global zone */ if (getzoneid() !=3D GLOBAL_ZONEID && !is_zoned) { (void) zfs_standard_error(hdl, EPERM, errbuf); zfs_close(zhp); return (-1); } /* make sure parent is a filesystem */ if (zfs_get_type(zhp) !=3D ZFS_TYPE_FILESYSTEM) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "parent is not a filesystem")); (void) zfs_error(hdl, EZFS_BADTYPE, errbuf); zfs_close(zhp); return (-1); } zfs_close(zhp); if (prefixlen !=3D NULL) *prefixlen =3D strlen(parent); return (0); } /* * Finds whether the dataset of the given type(s) exists. */ boolean_t zfs_dataset_exists(libzfs_handle_t *hdl, const char *path, zfs_type_t types= ) { zfs_handle_t *zhp; if (!zfs_validate_name(hdl, path, types, B_FALSE)) return (B_FALSE); /* * Try to get stats for the dataset, which will tell us if it exists. */ if ((zhp =3D make_dataset_handle(hdl, path)) !=3D NULL) { int ds_type =3D zhp->zfs_type; zfs_close(zhp); if (types & ds_type) return (B_TRUE); } return (B_FALSE); } /* * Given a path to 'target', create all the ancestors between * the prefixlen portion of the path, and the target itself. * Fail if the initial prefixlen-ancestor does not already exist. */ int create_parents(libzfs_handle_t *hdl, char *target, int prefixlen) { zfs_handle_t *h; char *cp; const char *opname; /* make sure prefix exists */ cp =3D target + prefixlen; if (*cp !=3D '/') { assert(strchr(cp, '/') =3D=3D NULL); h =3D zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); } else { *cp =3D '\0'; h =3D zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); *cp =3D '/'; } if (h =3D=3D NULL) return (-1); zfs_close(h); /* * Attempt to create, mount, and share any ancestor filesystems, * up to the prefixlen-long one. */ for (cp =3D target + prefixlen + 1; cp =3D strchr(cp, '/'); *cp =3D '/', cp++) { char *logstr; *cp =3D '\0'; h =3D make_dataset_handle(hdl, target); if (h) { /* it already exists, nothing to do here */ zfs_close(h); continue; } logstr =3D hdl->libzfs_log_str; hdl->libzfs_log_str =3D NULL; if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM, NULL) !=3D 0) { hdl->libzfs_log_str =3D logstr; opname =3D dgettext(TEXT_DOMAIN, "create"); goto ancestorerr; } hdl->libzfs_log_str =3D logstr; h =3D zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM); if (h =3D=3D NULL) { opname =3D dgettext(TEXT_DOMAIN, "open"); goto ancestorerr; } if (zfs_mount(h, NULL, 0) !=3D 0) { opname =3D dgettext(TEXT_DOMAIN, "mount"); goto ancestorerr; } if (zfs_share(h) !=3D 0) { opname =3D dgettext(TEXT_DOMAIN, "share"); goto ancestorerr; } zfs_close(h); } return (0); ancestorerr: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "failed to %s ancestor '%s'"), opname, target); return (-1); } /* * Creates non-existing ancestors of the given path. */ int zfs_create_ancestors(libzfs_handle_t *hdl, const char *path) { int prefix; char *path_copy; int rc; if (check_parents(hdl, path, NULL, B_TRUE, &prefix) !=3D 0) return (-1); if ((path_copy =3D strdup(path)) !=3D NULL) { rc =3D create_parents(hdl, path_copy, prefix); free(path_copy); } if (path_copy =3D=3D NULL || rc !=3D 0) return (-1); return (0); } /* * Create a new filesystem or volume. */ int zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, nvlist_t *props) { zfs_cmd_t zc =3D { 0 }; int ret; uint64_t size =3D 0; uint64_t blocksize =3D zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); char errbuf[1024]; uint64_t zoned; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot create '%s'"), path); /* validate the path, taking care to note the extended error message */ if (!zfs_validate_name(hdl, path, type, B_TRUE)) return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); /* validate parents exist */ if (check_parents(hdl, path, &zoned, B_FALSE, NULL) !=3D 0) return (-1); /* * The failure modes when creating a dataset of a different type over * one that already exists is a little strange. In particular, if you * try to create a dataset on top of an existing dataset, the ioctl() * will return ENOENT, not EEXIST. To prevent this from happening, we * first try to see if the dataset exists. */ (void) strlcpy(zc.zc_name, path, sizeof (zc.zc_name)); if (zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "dataset already exists")); return (zfs_error(hdl, EZFS_EXISTS, errbuf)); } if (type =3D=3D ZFS_TYPE_VOLUME) zc.zc_objset_type =3D DMU_OST_ZVOL; else zc.zc_objset_type =3D DMU_OST_ZFS; if (props && (props =3D zfs_valid_proplist(hdl, type, props, zoned, NULL, errbuf)) =3D=3D 0) return (-1); if (type =3D=3D ZFS_TYPE_VOLUME) { /* * If we are creating a volume, the size and block size must * satisfy a few restraints. First, the blocksize must be a * valid block size between SPA_{MIN,MAX}BLOCKSIZE. Second, the * volsize must be a multiple of the block size, and cannot be * zero. */ if (props =3D=3D NULL || nvlist_lookup_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) !=3D 0) { nvlist_free(props); zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "missing volume size")); return (zfs_error(hdl, EZFS_BADPROP, errbuf)); } if ((ret =3D nvlist_lookup_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), &blocksize)) !=3D 0) { if (ret =3D=3D ENOENT) { blocksize =3D zfs_prop_default_numeric( ZFS_PROP_VOLBLOCKSIZE); } else { nvlist_free(props); zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "missing volume block size")); return (zfs_error(hdl, EZFS_BADPROP, errbuf)); } } if (size =3D=3D 0) { nvlist_free(props); zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "volume size cannot be zero")); return (zfs_error(hdl, EZFS_BADPROP, errbuf)); } if (size % blocksize !=3D 0) { nvlist_free(props); zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "volume size must be a multiple of volume block " "size")); return (zfs_error(hdl, EZFS_BADPROP, errbuf)); } } if (props && zcmd_write_src_nvlist(hdl, &zc, props) !=3D 0) return (-1); nvlist_free(props); /* create the dataset */ ret =3D zfs_ioctl(hdl, ZFS_IOC_CREATE, &zc); zcmd_free_nvlists(&zc); /* check for failure */ if (ret !=3D 0) { char parent[ZFS_MAXNAMELEN]; (void) parent_name(path, parent, sizeof (parent)); switch (errno) { case ENOENT: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such parent '%s'"), parent); return (zfs_error(hdl, EZFS_NOENT, errbuf)); case EINVAL: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "parent '%s' is not a filesystem"), parent); return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); case EDOM: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "volume block size must be power of 2 from " "%u to %uk"), (uint_t)SPA_MINBLOCKSIZE, (uint_t)SPA_MAXBLOCKSIZE >> 10); return (zfs_error(hdl, EZFS_BADPROP, errbuf)); case ENOTSUP: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be upgraded to set this " "property or value")); return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); #ifdef _ILP32 case EOVERFLOW: /* * This platform can't address a volume this big. */ if (type =3D=3D ZFS_TYPE_VOLUME) return (zfs_error(hdl, EZFS_VOLTOOBIG, errbuf)); #endif /* FALLTHROUGH */ default: return (zfs_standard_error(hdl, errno, errbuf)); } } return (0); } /* * Destroys the given dataset. The caller must make sure that the filesyst= em * isn't mounted, and that there are no active dependents. */ int zfs_destroy(zfs_handle_t *zhp, boolean_t defer) { zfs_cmd_t zc =3D { 0 }; (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); if (ZFS_IS_VOLUME(zhp)) { zc.zc_objset_type =3D DMU_OST_ZVOL; } else { zc.zc_objset_type =3D DMU_OST_ZFS; } zc.zc_defer_destroy =3D defer; if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) !=3D 0) { return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), zhp->zfs_name)); } remove_mountpoint(zhp); return (0); } struct destroydata { nvlist_t *nvl; const char *snapname; }; static int zfs_check_snap_cb(zfs_handle_t *zhp, void *arg) { struct destroydata *dd =3D arg; zfs_handle_t *szhp; char name[ZFS_MAXNAMELEN]; int rv =3D 0; (void) snprintf(name, sizeof (name), "%s@%s", zhp->zfs_name, dd->snapname); szhp =3D make_dataset_handle(zhp->zfs_hdl, name); if (szhp) { verify(nvlist_add_boolean(dd->nvl, name) =3D=3D 0); zfs_close(szhp); } rv =3D zfs_iter_filesystems(zhp, zfs_check_snap_cb, dd); zfs_close(zhp); return (rv); } /* * Destroys all snapshots with the given name in zhp & descendants. */ int zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer) { int ret; struct destroydata dd =3D { 0 }; dd.snapname =3D snapname; verify(nvlist_alloc(&dd.nvl, NV_UNIQUE_NAME, 0) =3D=3D 0); (void) zfs_check_snap_cb(zfs_handle_dup(zhp), &dd); if (nvlist_next_nvpair(dd.nvl, NULL) =3D=3D NULL) { ret =3D zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT, dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"), zhp->zfs_name, snapname); } else { ret =3D zfs_destroy_snaps_nvl(zhp, dd.nvl, defer); } nvlist_free(dd.nvl); return (ret); } /* * Destroys all the snapshots named in the nvlist. They must be underneath * the zhp (either snapshots of it, or snapshots of its descendants). */ int zfs_destroy_snaps_nvl(zfs_handle_t *zhp, nvlist_t *snaps, boolean_t defer) { int ret; zfs_cmd_t zc =3D { 0 }; (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); if (zcmd_write_src_nvlist(zhp->zfs_hdl, &zc, snaps) !=3D 0) return (-1); zc.zc_defer_destroy =3D defer; ret =3D zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY_SNAPS_NVL, &zc); if (ret !=3D 0) { char errbuf[1024]; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot destroy snapshots in %s"), zc.zc_name); switch (errno) { case EEXIST: zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, "snapshot is cloned")); return (zfs_error(zhp->zfs_hdl, EZFS_EXISTS, errbuf)); default: return (zfs_standard_error(zhp->zfs_hdl, errno, errbuf)); } } return (0); } /* * Clones the given dataset. The target must be of the same type as the so= urce. */ int zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) { zfs_cmd_t zc =3D { 0 }; char parent[ZFS_MAXNAMELEN]; int ret; char errbuf[1024]; libzfs_handle_t *hdl =3D zhp->zfs_hdl; zfs_type_t type; uint64_t zoned; assert(zhp->zfs_type =3D=3D ZFS_TYPE_SNAPSHOT); (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot create '%s'"), target); /* validate the target/clone name */ if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE)) return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); /* validate parents exist */ if (check_parents(hdl, target, &zoned, B_FALSE, NULL) !=3D 0) return (-1); (void) parent_name(target, parent, sizeof (parent)); /* do the clone */ if (ZFS_IS_VOLUME(zhp)) { zc.zc_objset_type =3D DMU_OST_ZVOL; type =3D ZFS_TYPE_VOLUME; } else { zc.zc_objset_type =3D DMU_OST_ZFS; type =3D ZFS_TYPE_FILESYSTEM; } if (props) { if ((props =3D zfs_valid_proplist(hdl, type, props, zoned, zhp, errbuf)) =3D=3D NULL) return (-1); if (zcmd_write_src_nvlist(hdl, &zc, props) !=3D 0) { nvlist_free(props); return (-1); } nvlist_free(props); } (void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name)); (void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value)); ret =3D zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_CREATE, &zc); zcmd_free_nvlists(&zc); if (ret !=3D 0) { switch (errno) { case ENOENT: /* * The parent doesn't exist. We should have caught this * above, but there may a race condition that has since * destroyed the parent. * * At this point, we don't know whether it's the source * that doesn't exist anymore, or whether the target * dataset doesn't exist. */ zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, "no such parent '%s'"), parent); return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf)); case EXDEV: zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, "source and target pools differ")); return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET, errbuf)); default: return (zfs_standard_error(zhp->zfs_hdl, errno, errbuf)); } } return (ret); } /* * Promotes the given clone fs to be the clone parent. */ int zfs_promote(zfs_handle_t *zhp) { libzfs_handle_t *hdl =3D zhp->zfs_hdl; zfs_cmd_t zc =3D { 0 }; char parent[MAXPATHLEN]; int ret; char errbuf[1024]; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot promote '%s'"), zhp->zfs_name); if (zhp->zfs_type =3D=3D ZFS_TYPE_SNAPSHOT) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "snapshots can not be promoted")); return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); } (void) strlcpy(parent, zhp->zfs_dmustats.dds_origin, sizeof (parent)); if (parent[0] =3D=3D '\0') { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "not a cloned filesystem")); return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); } (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_origin, sizeof (zc.zc_value)); (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); ret =3D zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc); if (ret !=3D 0) { int save_errno =3D errno; switch (save_errno) { case EEXIST: /* There is a conflicting snapshot name. */ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "conflicting snapshot '%s' from parent '%s'"), zc.zc_string, parent); return (zfs_error(hdl, EZFS_EXISTS, errbuf)); default: return (zfs_standard_error(hdl, save_errno, errbuf)); } } return (ret); } /* * Takes a snapshot of the given dataset. */ int zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive, nvlist_t *props) { const char *delim; char parent[ZFS_MAXNAMELEN]; zfs_handle_t *zhp; zfs_cmd_t zc =3D { 0 }; int ret; char errbuf[1024]; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot snapshot '%s'"), path); /* validate the target name */ if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE)) return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); if (props) { if ((props =3D zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT, props, B_FALSE, NULL, errbuf)) =3D=3D NULL) return (-1); if (zcmd_write_src_nvlist(hdl, &zc, props) !=3D 0) { nvlist_free(props); return (-1); } nvlist_free(props); } /* make sure the parent exists and is of the appropriate type */ delim =3D strchr(path, '@'); (void) strncpy(parent, path, delim - path); parent[delim - path] =3D '\0'; if ((zhp =3D zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) =3D=3D NULL) { zcmd_free_nvlists(&zc); return (-1); } (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); (void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value)); if (ZFS_IS_VOLUME(zhp)) zc.zc_objset_type =3D DMU_OST_ZVOL; else zc.zc_objset_type =3D DMU_OST_ZFS; zc.zc_cookie =3D recursive; ret =3D zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SNAPSHOT, &zc); zcmd_free_nvlists(&zc); /* * if it was recursive, the one that actually failed will be in * zc.zc_name. */ if (ret !=3D 0) { (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value); (void) zfs_standard_error(hdl, errno, errbuf); } zfs_close(zhp); return (ret); } /* * Destroy any more recent snapshots. We invoke this callback on any depen= dents * of the snapshot first. If the 'cb_dependent' member is non-zero, then t= his * is a dependent and we should just destroy it without checking the transa= ction * group. */ typedef struct rollback_data { const char *cb_target; /* the snapshot */ uint64_t cb_create; /* creation time reference */ boolean_t cb_error; boolean_t cb_dependent; boolean_t cb_force; } rollback_data_t; static int rollback_destroy(zfs_handle_t *zhp, void *data) { rollback_data_t *cbp =3D data; if (!cbp->cb_dependent) { if (strcmp(zhp->zfs_name, cbp->cb_target) !=3D 0 && zfs_get_type(zhp) =3D=3D ZFS_TYPE_SNAPSHOT && zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > cbp->cb_create) { char *logstr; cbp->cb_dependent =3D B_TRUE; cbp->cb_error |=3D zfs_iter_dependents(zhp, B_FALSE, rollback_destroy, cbp); cbp->cb_dependent =3D B_FALSE; logstr =3D zhp->zfs_hdl->libzfs_log_str; zhp->zfs_hdl->libzfs_log_str =3D NULL; cbp->cb_error |=3D zfs_destroy(zhp, B_FALSE); zhp->zfs_hdl->libzfs_log_str =3D logstr; } } else { /* We must destroy this clone; first unmount it */ prop_changelist_t *clp; clp =3D changelist_gather(zhp, ZFS_PROP_NAME, 0, cbp->cb_force ? MS_FORCE: 0); if (clp =3D=3D NULL || changelist_prefix(clp) !=3D 0) { cbp->cb_error =3D B_TRUE; zfs_close(zhp); return (0); } if (zfs_destroy(zhp, B_FALSE) !=3D 0) cbp->cb_error =3D B_TRUE; else changelist_remove(clp, zhp->zfs_name); (void) changelist_postfix(clp); changelist_free(clp); } zfs_close(zhp); return (0); } /* * Given a dataset, rollback to a specific snapshot, discarding any * data changes since then and making it the active dataset. * * Any snapshots more recent than the target are destroyed, along with * their dependents. */ int zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force) { rollback_data_t cb =3D { 0 }; int err; zfs_cmd_t zc =3D { 0 }; boolean_t restore_resv =3D 0; uint64_t old_volsize, new_volsize; zfs_prop_t resv_prop; assert(zhp->zfs_type =3D=3D ZFS_TYPE_FILESYSTEM || zhp->zfs_type =3D=3D ZFS_TYPE_VOLUME); /* * Destroy all recent snapshots and its dependends. */ cb.cb_force =3D force; cb.cb_target =3D snap->zfs_name; cb.cb_create =3D zfs_prop_get_int(snap, ZFS_PROP_CREATETXG); (void) zfs_iter_children(zhp, rollback_destroy, &cb); if (cb.cb_error) return (-1); /* * Now that we have verified that the snapshot is the latest, * rollback to the given snapshot. */ if (zhp->zfs_type =3D=3D ZFS_TYPE_VOLUME) { if (zfs_which_resv_prop(zhp, &resv_prop) < 0) return (-1); old_volsize =3D zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); restore_resv =3D (old_volsize =3D=3D zfs_prop_get_int(zhp, resv_prop)); } (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); if (ZFS_IS_VOLUME(zhp)) zc.zc_objset_type =3D DMU_OST_ZVOL; else zc.zc_objset_type =3D DMU_OST_ZFS; /* * We rely on zfs_iter_children() to verify that there are no * newer snapshots for the given dataset. Therefore, we can * simply pass the name on to the ioctl() call. There is still * an unlikely race condition where the user has taken a * snapshot since we verified that this was the most recent. * */ if ((err =3D zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_ROLLBACK, &zc)) !=3D 0) { (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno, dgettext(TEXT_DOMAIN, "cannot rollback '%s'"), zhp->zfs_name); return (err); } /* * For volumes, if the pre-rollback volsize matched the pre- * rollback reservation and the volsize has changed then set * the reservation property to the post-rollback volsize. * Make a new handle since the rollback closed the dataset. */ if ((zhp->zfs_type =3D=3D ZFS_TYPE_VOLUME) && (zhp =3D make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) { if (restore_resv) { new_volsize =3D zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE); if (old_volsize !=3D new_volsize) err =3D zfs_prop_set_int(zhp, resv_prop, new_volsize); } zfs_close(zhp); } return (err); } /* * Renames the given dataset. */ int zfs_rename(zfs_handle_t *zhp, const char *target, renameflags_t flags) { int ret; zfs_cmd_t zc =3D { 0 }; char *delim; prop_changelist_t *cl =3D NULL; zfs_handle_t *zhrp =3D NULL; char *parentname =3D NULL; char parent[ZFS_MAXNAMELEN]; char property[ZFS_MAXPROPLEN]; libzfs_handle_t *hdl =3D zhp->zfs_hdl; char errbuf[1024]; /* if we have the same exact name, just return success */ if (strcmp(zhp->zfs_name, target) =3D=3D 0) return (0); (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot rename to '%s'"), target); /* * Make sure the target name is valid */ if (zhp->zfs_type =3D=3D ZFS_TYPE_SNAPSHOT) { if ((strchr(target, '@') =3D=3D NULL) || *target =3D=3D '@') { /* * Snapshot target name is abbreviated, * reconstruct full dataset name */ (void) strlcpy(parent, zhp->zfs_name, sizeof (parent)); delim =3D strchr(parent, '@'); if (strchr(target, '@') =3D=3D NULL) *(++delim) =3D '\0'; else *delim =3D '\0'; (void) strlcat(parent, target, sizeof (parent)); target =3D parent; } else { /* * Make sure we're renaming within the same dataset. */ delim =3D strchr(target, '@'); if (strncmp(zhp->zfs_name, target, delim - target) !=3D 0 || zhp->zfs_name[delim - target] !=3D '@') { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "snapshots must be part of same " "dataset")); return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); } } if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); } else { if (flags.recurse) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "recursive rename must be a snapshot")); return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); } if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE)) return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); /* validate parents */ if (check_parents(hdl, target, NULL, B_FALSE, NULL) !=3D 0) return (-1); /* make sure we're in the same pool */ verify((delim =3D strchr(target, '/')) !=3D NULL); if (strncmp(zhp->zfs_name, target, delim - target) !=3D 0 || zhp->zfs_name[delim - target] !=3D '/') { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "datasets must be within same pool")); return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf)); } /* new name cannot be a child of the current dataset name */ if (is_descendant(zhp->zfs_name, target)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "New dataset name cannot be a descendant of " "current dataset name")); return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); } } (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name); if (getzoneid() =3D=3D GLOBAL_ZONEID && zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "dataset is used in a non-global zone")); return (zfs_error(hdl, EZFS_ZONED, errbuf)); } /* * Avoid unmounting file systems with mountpoint property set to * 'legacy' or 'none' even if -u option is not given. */ if (zhp->zfs_type =3D=3D ZFS_TYPE_FILESYSTEM && !flags.recurse && !flags.nounmount && zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, property, sizeof (property), NULL, NULL, 0, B_FALSE) =3D=3D 0 && (strcmp(property, "legacy") =3D=3D 0 || strcmp(property, "none") =3D=3D 0)) { flags.nounmount =3D B_TRUE; } if (flags.recurse) { parentname =3D zfs_strdup(zhp->zfs_hdl, zhp->zfs_name); if (parentname =3D=3D NULL) { ret =3D -1; goto error; } delim =3D strchr(parentname, '@'); *delim =3D '\0'; zhrp =3D zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_DATASET); if (zhrp =3D=3D NULL) { ret =3D -1; goto error; } } else { if ((cl =3D changelist_gather(zhp, ZFS_PROP_NAME, flags.nounmount ? CL_GATHER_DONT_UNMOUNT : 0, flags.forceunmount ? MS_FORCE : 0)) =3D=3D NULL) { return (-1); } if (changelist_haszonedchild(cl)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "child dataset with inherited mountpoint is used " "in a non-global zone")); (void) zfs_error(hdl, EZFS_ZONED, errbuf); goto error; } if ((ret =3D changelist_prefix(cl)) !=3D 0) goto error; } if (ZFS_IS_VOLUME(zhp)) zc.zc_objset_type =3D DMU_OST_ZVOL; else zc.zc_objset_type =3D DMU_OST_ZFS; (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value)); zc.zc_cookie =3D flags.recurse ? 1 : 0; if (flags.nounmount) zc.zc_cookie |=3D 2; if ((ret =3D zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) !=3D 0) { /* * if it was recursive, the one that actually failed will * be in zc.zc_name */ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zc.zc_name); if (flags.recurse && errno =3D=3D EEXIST) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "a child dataset already has a snapshot " "with the new name")); (void) zfs_error(hdl, EZFS_EXISTS, errbuf); } else { (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf); } /* * On failure, we still want to remount any filesystems that * were previously mounted, so we don't alter the system state. */ if (!flags.recurse) (void) changelist_postfix(cl); } else { if (!flags.recurse) { changelist_rename(cl, zfs_get_name(zhp), target); ret =3D changelist_postfix(cl); } } error: if (parentname) { free(parentname); } if (zhrp) { zfs_close(zhrp); } if (cl) { changelist_free(cl); } return (ret); } nvlist_t * zfs_get_user_props(zfs_handle_t *zhp) { return (zhp->zfs_user_props); } nvlist_t * zfs_get_recvd_props(zfs_handle_t *zhp) { if (zhp->zfs_recvd_props =3D=3D NULL) if (get_recvd_props_ioctl(zhp) !=3D 0) return (NULL); return (zhp->zfs_recvd_props); } /* * This function is used by 'zfs list' to determine the exact set of column= s to * display, and their maximum widths. This does two main things: * * - If this is a list of all properties, then expand the list to incl= ude * all native properties, and set a flag so that for each dataset we= look * for new unique user properties and add them to the list. * * - For non fixed-width properties, keep track of the maximum width s= een * so that we can size the column appropriately. If the user has * requested received property values, we also need to compute the w= idth * of the RECEIVED column. */ int zfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t receiv= ed) { libzfs_handle_t *hdl =3D zhp->zfs_hdl; zprop_list_t *entry; zprop_list_t **last, **start; nvlist_t *userprops, *propval; nvpair_t *elem; char *strval; char buf[ZFS_MAXPROPLEN]; if (zprop_expand_list(hdl, plp, ZFS_TYPE_DATASET) !=3D 0) return (-1); userprops =3D zfs_get_user_props(zhp); entry =3D *plp; if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) !=3D NULL) { /* * Go through and add any user properties as necessary. We * start by incrementing our list pointer to the first * non-native property. */ start =3D plp; while (*start !=3D NULL) { if ((*start)->pl_prop =3D=3D ZPROP_INVAL) break; start =3D &(*start)->pl_next; } elem =3D NULL; while ((elem =3D nvlist_next_nvpair(userprops, elem)) !=3D NULL) { /* * See if we've already found this property in our list. */ for (last =3D start; *last !=3D NULL; last =3D &(*last)->pl_next) { if (strcmp((*last)->pl_user_prop, nvpair_name(elem)) =3D=3D 0) break; } if (*last =3D=3D NULL) { if ((entry =3D zfs_alloc(hdl, sizeof (zprop_list_t))) =3D=3D NULL || ((entry->pl_user_prop =3D zfs_strdup(hdl, nvpair_name(elem)))) =3D=3D NULL) { free(entry); return (-1); } entry->pl_prop =3D ZPROP_INVAL; entry->pl_width =3D strlen(nvpair_name(elem)); entry->pl_all =3D B_TRUE; *last =3D entry; } } } /* * Now go through and check the width of any non-fixed columns */ for (entry =3D *plp; entry !=3D NULL; entry =3D entry->pl_next) { if (entry->pl_fixed) continue; if (entry->pl_prop !=3D ZPROP_INVAL) { if (zfs_prop_get(zhp, entry->pl_prop, buf, sizeof (buf), NULL, NULL, 0, B_FALSE) =3D=3D 0) { if (strlen(buf) > entry->pl_width) entry->pl_width =3D strlen(buf); } if (received && zfs_prop_get_recvd(zhp, zfs_prop_to_name(entry->pl_prop), buf, sizeof (buf), B_FALSE) =3D=3D 0) if (strlen(buf) > entry->pl_recvd_width) entry->pl_recvd_width =3D strlen(buf); } else { if (nvlist_lookup_nvlist(userprops, entry->pl_user_prop, &propval) =3D=3D 0) { verify(nvlist_lookup_string(propval, ZPROP_VALUE, &strval) =3D=3D 0); if (strlen(strval) > entry->pl_width) entry->pl_width =3D strlen(strval); } if (received && zfs_prop_get_recvd(zhp, entry->pl_user_prop, buf, sizeof (buf), B_FALSE) =3D=3D 0) if (strlen(buf) > entry->pl_recvd_width) entry->pl_recvd_width =3D strlen(buf); } } return (0); } int zfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path, char *resource, void *export, void *sharetab, int sharemax, zfs_share_op_t operation) { zfs_cmd_t zc =3D { 0 }; int error; (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); if (resource) (void) strlcpy(zc.zc_string, resource, sizeof (zc.zc_string)); zc.zc_share.z_sharedata =3D (uint64_t)(uintptr_t)sharetab; zc.zc_share.z_exportdata =3D (uint64_t)(uintptr_t)export; zc.zc_share.z_sharetype =3D operation; zc.zc_share.z_sharemax =3D sharemax; error =3D ioctl(hdl->libzfs_fd, ZFS_IOC_SHARE, &zc); return (error); } void zfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props) { nvpair_t *curr; /* * Keep a reference to the props-table against which we prune the * properties. */ zhp->zfs_props_table =3D props; curr =3D nvlist_next_nvpair(zhp->zfs_props, NULL); while (curr) { zfs_prop_t zfs_prop =3D zfs_name_to_prop(nvpair_name(curr)); nvpair_t *next =3D nvlist_next_nvpair(zhp->zfs_props, curr); /* * User properties will result in ZPROP_INVAL, and since we * only know how to prune standard ZFS properties, we always * leave these in the list. This can also happen if we * encounter an unknown DSL property (when running older * software, for example). */ if (zfs_prop !=3D ZPROP_INVAL && props[zfs_prop] =3D=3D B_FALSE) (void) nvlist_remove(zhp->zfs_props, nvpair_name(curr), nvpair_type(curr)); curr =3D next; } } #ifdef sun static int zfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path, zfs_smb_acl_op_t cmd, char *resource1, char *resource2) { zfs_cmd_t zc =3D { 0 }; nvlist_t *nvlist =3D NULL; int error; (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value)); zc.zc_cookie =3D (uint64_t)cmd; if (cmd =3D=3D ZFS_SMB_ACL_RENAME) { if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) !=3D 0) { (void) no_memory(hdl); return (NULL); } } switch (cmd) { case ZFS_SMB_ACL_ADD: case ZFS_SMB_ACL_REMOVE: (void) strlcpy(zc.zc_string, resource1, sizeof (zc.zc_string)); break; case ZFS_SMB_ACL_RENAME: if (nvlist_add_string(nvlist, ZFS_SMB_ACL_SRC, resource1) !=3D 0) { (void) no_memory(hdl); return (-1); } if (nvlist_add_string(nvlist, ZFS_SMB_ACL_TARGET, resource2) !=3D 0) { (void) no_memory(hdl); return (-1); } if (zcmd_write_src_nvlist(hdl, &zc, nvlist) !=3D 0) { nvlist_free(nvlist); return (-1); } break; case ZFS_SMB_ACL_PURGE: break; default: return (-1); } error =3D ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc); if (nvlist) nvlist_free(nvlist); return (error); } int zfs_smb_acl_add(libzfs_handle_t *hdl, char *dataset, char *path, char *resource) { return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_ADD, resource, NULL)); } int zfs_smb_acl_remove(libzfs_handle_t *hdl, char *dataset, char *path, char *resource) { return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_REMOVE, resource, NULL)); } int zfs_smb_acl_purge(libzfs_handle_t *hdl, char *dataset, char *path) { return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_PURGE, NULL, NULL)); } int zfs_smb_acl_rename(libzfs_handle_t *hdl, char *dataset, char *path, char *oldname, char *newname) { return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME, oldname, newname)); } #endif /* sun */ int zfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type, zfs_userspace_cb_t func, void *arg) { zfs_cmd_t zc =3D { 0 }; int error; zfs_useracct_t buf[100]; (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); zc.zc_objset_type =3D type; zc.zc_nvlist_dst =3D (uintptr_t)buf; /* CONSTCOND */ while (1) { zfs_useracct_t *zua =3D buf; zc.zc_nvlist_dst_size =3D sizeof (buf); error =3D ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_MANY, &zc); if (error || zc.zc_nvlist_dst_size =3D=3D 0) break; while (zc.zc_nvlist_dst_size > 0) { error =3D func(arg, zua->zu_domain, zua->zu_rid, zua->zu_space); if (error !=3D 0) return (error); zua++; zc.zc_nvlist_dst_size -=3D sizeof (zfs_useracct_t); } } return (error); } int zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag, boolean_t recursive, boolean_t temphold, boolean_t enoent_ok, int cleanup_fd, uint64_t dsobj, uint64_t createtxg) { zfs_cmd_t zc =3D { 0 }; libzfs_handle_t *hdl =3D zhp->zfs_hdl; ASSERT(!recursive || dsobj =3D=3D 0); (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); if (strlcpy(zc.zc_string, tag, sizeof (zc.zc_string)) >=3D sizeof (zc.zc_string)) return (zfs_error(hdl, EZFS_TAGTOOLONG, tag)); zc.zc_cookie =3D recursive; zc.zc_temphold =3D temphold; zc.zc_cleanup_fd =3D cleanup_fd; zc.zc_sendobj =3D dsobj; zc.zc_createtxg =3D createtxg; if (zfs_ioctl(hdl, ZFS_IOC_HOLD, &zc) !=3D 0) { char errbuf[ZFS_MAXNAMELEN+32]; /* * if it was recursive, the one that actually failed will be in * zc.zc_name. */ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot hold '%s@%s'"), zc.zc_name, snapname); switch (errno) { case E2BIG: /* * Temporary tags wind up having the ds object id * prepended. So even if we passed the length check * above, it's still possible for the tag to wind * up being slightly too long. */ return (zfs_error(hdl, EZFS_TAGTOOLONG, errbuf)); case ENOTSUP: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be upgraded")); return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); case EINVAL: return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); case EEXIST: return (zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf)); case ENOENT: if (enoent_ok) return (ENOENT); /* FALLTHROUGH */ default: return (zfs_standard_error_fmt(hdl, errno, errbuf)); } } return (0); } int zfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag, boolean_t recursive) { zfs_cmd_t zc =3D { 0 }; libzfs_handle_t *hdl =3D zhp->zfs_hdl; (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); if (strlcpy(zc.zc_string, tag, sizeof (zc.zc_string)) >=3D sizeof (zc.zc_string)) return (zfs_error(hdl, EZFS_TAGTOOLONG, tag)); zc.zc_cookie =3D recursive; if (zfs_ioctl(hdl, ZFS_IOC_RELEASE, &zc) !=3D 0) { char errbuf[ZFS_MAXNAMELEN+32]; /* * if it was recursive, the one that actually failed will be in * zc.zc_name. */ (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot release '%s' from '%s@%s'"), tag, zc.zc_name, snapname); switch (errno) { case ESRCH: return (zfs_error(hdl, EZFS_REFTAG_RELE, errbuf)); case ENOTSUP: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be upgraded")); return (zfs_error(hdl, EZFS_BADVERSION, errbuf)); case EINVAL: return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); default: return (zfs_standard_error_fmt(hdl, errno, errbuf)); } } return (0); } int zfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl) { zfs_cmd_t zc =3D { 0 }; libzfs_handle_t *hdl =3D zhp->zfs_hdl; int nvsz =3D 2048; void *nvbuf; int err =3D 0; char errbuf[ZFS_MAXNAMELEN+32]; assert(zhp->zfs_type =3D=3D ZFS_TYPE_VOLUME || zhp->zfs_type =3D=3D ZFS_TYPE_FILESYSTEM); tryagain: nvbuf =3D malloc(nvsz); if (nvbuf =3D=3D NULL) { err =3D (zfs_error(hdl, EZFS_NOMEM, strerror(errno))); goto out; } zc.zc_nvlist_dst_size =3D nvsz; zc.zc_nvlist_dst =3D (uintptr_t)nvbuf; (void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN); if (ioctl(hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) !=3D 0) { (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"), zc.zc_name); switch (errno) { case ENOMEM: free(nvbuf); nvsz =3D zc.zc_nvlist_dst_size; goto tryagain; case ENOTSUP: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be upgraded")); err =3D zfs_error(hdl, EZFS_BADVERSION, errbuf); break; case EINVAL: err =3D zfs_error(hdl, EZFS_BADTYPE, errbuf); break; case ENOENT: err =3D zfs_error(hdl, EZFS_NOENT, errbuf); break; default: err =3D zfs_standard_error_fmt(hdl, errno, errbuf); break; } } else { /* success */ int rc =3D nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0); if (rc) { (void) snprintf(errbuf, sizeof (errbuf), dgettext( TEXT_DOMAIN, "cannot get permissions on '%s'"), zc.zc_name); err =3D zfs_standard_error_fmt(hdl, rc, errbuf); } } free(nvbuf); out: return (err); } int zfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl) { zfs_cmd_t zc =3D { 0 }; libzfs_handle_t *hdl =3D zhp->zfs_hdl; char *nvbuf; char errbuf[ZFS_MAXNAMELEN+32]; size_t nvsz; int err; assert(zhp->zfs_type =3D=3D ZFS_TYPE_VOLUME || zhp->zfs_type =3D=3D ZFS_TYPE_FILESYSTEM); err =3D nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE); assert(err =3D=3D 0); nvbuf =3D malloc(nvsz); err =3D nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0); assert(err =3D=3D 0); zc.zc_nvlist_src_size =3D nvsz; zc.zc_nvlist_src =3D (uintptr_t)nvbuf; zc.zc_perm_action =3D un; (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); if (zfs_ioctl(hdl, ZFS_IOC_SET_FSACL, &zc) !=3D 0) { (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot set permissions on '%s'"), zc.zc_name); switch (errno) { case ENOTSUP: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be upgraded")); err =3D zfs_error(hdl, EZFS_BADVERSION, errbuf); break; case EINVAL: err =3D zfs_error(hdl, EZFS_BADTYPE, errbuf); break; case ENOENT: err =3D zfs_error(hdl, EZFS_NOENT, errbuf); break; default: err =3D zfs_standard_error_fmt(hdl, errno, errbuf); break; } } free(nvbuf); return (err); } int zfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl) { zfs_cmd_t zc =3D { 0 }; libzfs_handle_t *hdl =3D zhp->zfs_hdl; int nvsz =3D 2048; void *nvbuf; int err =3D 0; char errbuf[ZFS_MAXNAMELEN+32]; assert(zhp->zfs_type =3D=3D ZFS_TYPE_SNAPSHOT); tryagain: nvbuf =3D malloc(nvsz); if (nvbuf =3D=3D NULL) { err =3D (zfs_error(hdl, EZFS_NOMEM, strerror(errno))); goto out; } zc.zc_nvlist_dst_size =3D nvsz; zc.zc_nvlist_dst =3D (uintptr_t)nvbuf; (void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN); if (zfs_ioctl(hdl, ZFS_IOC_GET_HOLDS, &zc) !=3D 0) { (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"), zc.zc_name); switch (errno) { case ENOMEM: free(nvbuf); nvsz =3D zc.zc_nvlist_dst_size; goto tryagain; case ENOTSUP: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be upgraded")); err =3D zfs_error(hdl, EZFS_BADVERSION, errbuf); break; case EINVAL: err =3D zfs_error(hdl, EZFS_BADTYPE, errbuf); break; case ENOENT: err =3D zfs_error(hdl, EZFS_NOENT, errbuf); break; default: err =3D zfs_standard_error_fmt(hdl, errno, errbuf); break; } } else { /* success */ int rc =3D nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0); if (rc) { (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"), zc.zc_name); err =3D zfs_standard_error_fmt(hdl, rc, errbuf); } } free(nvbuf); out: return (err); } uint64_t zvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props) { uint64_t numdb; uint64_t nblocks, volblocksize; int ncopies; char *strval; if (nvlist_lookup_string(props, zfs_prop_to_name(ZFS_PROP_COPIES), &strval) =3D=3D 0) ncopies =3D atoi(strval); else ncopies =3D 1; if (nvlist_lookup_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), &volblocksize) !=3D 0) volblocksize =3D ZVOL_DEFAULT_BLOCKSIZE; nblocks =3D volsize/volblocksize; /* start with metadnode L0-L6 */ numdb =3D 7; /* calculate number of indirects */ while (nblocks > 1) { nblocks +=3D DNODES_PER_LEVEL - 1; nblocks /=3D DNODES_PER_LEVEL; numdb +=3D nblocks; } numdb *=3D MIN(SPA_DVAS_PER_BP, ncopies + 1); volsize *=3D ncopies; /* * this is exactly DN_MAX_INDBLKSHIFT when metadata isn't * compressed, but in practice they compress down to about * 1100 bytes */ numdb *=3D 1ULL << DN_MAX_INDBLKSHIFT; volsize +=3D numdb; return (volsize); } /* * Attach/detach the given filesystem to/from the given jail. */ int zfs_jail(zfs_handle_t *zhp, int jailid, int attach) { libzfs_handle_t *hdl =3D zhp->zfs_hdl; zfs_cmd_t zc =3D { 0 }; char errbuf[1024]; unsigned long cmd; int ret; if (attach) { (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name); } else { (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot jail '%s'"), zhp->zfs_name); } switch (zhp->zfs_type) { case ZFS_TYPE_VOLUME: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "volumes can not be jailed")); return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); case ZFS_TYPE_SNAPSHOT: zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "snapshots can not be jailed")); return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); } assert(zhp->zfs_type =3D=3D ZFS_TYPE_FILESYSTEM); (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); zc.zc_objset_type =3D DMU_OST_ZFS; zc.zc_jailid =3D jailid; cmd =3D attach ? ZFS_IOC_JAIL : ZFS_IOC_UNJAIL; if ((ret =3D ioctl(hdl->libzfs_fd, cmd, &zc)) !=3D 0) zfs_standard_error(hdl, errno, errbuf); return (ret); } --=-eOAg1opG/d7eXMURa76A-- From owner-freebsd-fs@FreeBSD.ORG Wed Jun 13 11:02:33 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 6C480106566C for ; Wed, 13 Jun 2012 11:02:33 +0000 (UTC) (envelope-from i.junus@gmail.com) Received: from mail-we0-f182.google.com (mail-we0-f182.google.com [74.125.82.182]) by mx1.freebsd.org (Postfix) with ESMTP id E80EA8FC14 for ; Wed, 13 Jun 2012 11:02:32 +0000 (UTC) Received: by werg1 with SMTP id g1so461900wer.13 for ; Wed, 13 Jun 2012 04:02:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=JOraypReyVHMyYYNGno01SOppFJuz6ONnc5rX/5jZM4=; b=uiHqq/0sVwLkh9c+7i94Pjkv+N3a9/ZvMyOIOM8KnjOM/V0TAzqZMv0sv9Y++Ll8Nq iRSyaU3G74JsHUahk2ocHjDVv86jicePTYIgM54qBIP8YZbKJOaVO4ThVfZWomWDJFsi bruLgagrs1GGsgdH2B+yr/ZULGKWifJzYK5aaCYNxFAccT9VAblUpjdOeZf0hP7zCeXY EkxVVPSM0C8rT/gSlrJVJ3drNIBf5ymijVBbha2A6GjEbBdaZZp61EZG9uLspbZDMr+8 dnrr/YkEjZ2LHrnLiHmKvPQsig7wT6sU+YuBXmVcxz08lxk/ybvdWdgFUWFGAcX0RuY6 EB9A== MIME-Version: 1.0 Received: by 10.180.78.228 with SMTP id e4mr36921420wix.4.1339585351670; Wed, 13 Jun 2012 04:02:31 -0700 (PDT) Received: by 10.194.33.42 with HTTP; Wed, 13 Jun 2012 04:02:31 -0700 (PDT) In-Reply-To: References: Date: Wed, 13 Jun 2012 19:02:31 +0800 Message-ID: From: Irjohn Junus To: Olivier Smedts Content-Type: text/plain; charset=ISO-8859-1 X-Content-Filtered-By: Mailman/MimeDel 2.1.5 Cc: freebsd-fs@freebsd.org Subject: Re: gpart add -a 4096 vs 4k X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 13 Jun 2012 11:02:33 -0000 Olivier, Thanks for your quick reply and you're right, '4k' = '8'! # gpart add -t freebsd-zfs -l hdd0 -a 8 da0 da0p1 added # gpart show da0 => 34 3907029101 da0 GPT (1.8T) 34 6 - free - (3.0k) 40 3907029088 1 freebsd-zfs (1.8T) 3907029128 7 - free - (3.5k) Thanks, Ronjns On Wed, Jun 13, 2012 at 6:18 PM, Olivier Smedts wrote: > Hello, > > 2012/6/13 Irjohn Junus : > > Hello, > > > > Relatively new to FreeBSD and learning, I'm trying to partition my HDD > and > > align it to 4k sector. > > > > I do apologize if this has been answered before, I have Googled and read > > gpart(8) man page to no joy. Can anyone please advice why gpart add '-a > > 4096' doesn't yield the same result with '-a 4k'? Many thanks and > captures > > are below. > > > > Regards, > > Ronjns > > > > > > > > #gpart add -t freebsd-zfs -l hdd0 *-a 4096* da0 > > da0p1 added > > # gpart show da0 > > => 34 3907029101 da0 GPT (1.8T) > > 34 4062 - free - (2M) > > *4096 3907022848* 1 freebsd-zfs (1.8T) > > 3907026944 2191 - free - (1.1M) > > > > > > > > # gpart add -t freebsd-zfs -l hdd0 *-a 4k* da0 > > da0p1 added > > # gpart show da0 > > => 34 3907029101 da0 GPT (1.8T) > > 34 6 - free - (3.0k) > > *40 3907029088* 1 freebsd-zfs (1.8T) > > 3907029128 7 - free - (3.5k) > > We're talking of sectors here, se "4096" does not mean 4 KB but > 4096*512=2MB. > > I think you should use "-a 8", because 4k sectors = 8*512B sectors. > > -- > Olivier Smedts _ > ASCII ribbon campaign ( ) > e-mail: olivier@gid0.org - against HTML email & vCards X > www: http://www.gid0.org - against proprietary attachments / \ > > "Il y a seulement 10 sortes de gens dans le monde : > ceux qui comprennent le binaire, > et ceux qui ne le comprennent pas." > From owner-freebsd-fs@FreeBSD.ORG Wed Jun 13 14:23:14 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (unknown [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 1ED371065689 for ; Wed, 13 Jun 2012 14:23:14 +0000 (UTC) (envelope-from marc@mpeters.org) Received: from mail.mpeters.org (mail.mpeters.org [78.46.104.142]) by mx1.freebsd.org (Postfix) with ESMTP id 9ADB78FC08 for ; Wed, 13 Jun 2012 14:23:13 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by mail.mpeters.org (Postfix) with ESMTP id BF79113203D for ; Wed, 13 Jun 2012 16:23:06 +0200 (CEST) X-Virus-Scanned: amavisd-new at mpeters.org Received: from mail.mpeters.org ([127.0.0.1]) by localhost (mail.mpeters.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id IKs7QgGbTyU1 for ; Wed, 13 Jun 2012 16:23:04 +0200 (CEST) Received: from [192.168.0.204] (unknown [62.159.86.18]) by mail.mpeters.org (Postfix) with ESMTPSA id 9EDC2132038 for ; Wed, 13 Jun 2012 16:23:04 +0200 (CEST) Message-ID: <4FD8A246.9060901@mpeters.org> Date: Wed, 13 Jun 2012 16:23:02 +0200 From: Marc Peters User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:10.0.4) Gecko/20120513 Thunderbird/10.0.4 MIME-Version: 1.0 To: freebsd-fs@freebsd.org References: <4FD74858.6070705@mpeters.org> <20120612164206.6a573136@fabiankeil.de> In-Reply-To: X-Enigmail-Version: 1.3.5 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Subject: Re: ZFS deletes ACLs when root edits a file X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 13 Jun 2012 14:23:14 -0000 -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 06/12/2012 09:15 PM, Andrew Leonard wrote: > On Tue, Jun 12, 2012 at 7:42 AM, Fabian Keil > wrote: > >> Marc Peters wrote: >> >>> i observed a strange behaviour when using ACLs on a ZFS >>> filesystem. When a file has ACLs set and is edited by a user, >>> the ACLs get lost when the file is edited and saved. >>> >>> How to repeat: >>> >>>> mount >>> /dev/aacd0s1a on / (ufs, local) devfs on /dev (devfs, local, >>> multilabel) /dev/aacd0s1d on /var (ufs, local, soft-updates) >>> appdata on /appdata (zfs, local, nfsv4acls) /dev/md0 on >>> /appdata/www/cache (ufs, local, soft-updates) >>> >>>> ls -al >>> total 3 drwxr-xr-x 2 mpeters wheel 2 Jun 12 15:31 . >>> drwxr-xr-x 5 root wheel 5 Jun 12 15:29 .. >>>> touch test.file ls -al >>> total 4 drwxr-xr-x 2 mpeters wheel 3 Jun 12 15:32 . >>> drwxr-xr-x 5 root wheel 5 Jun 12 15:29 .. - -rw-r--r-- 1 >>> mpeters wheel 0 Jun 12 15:32 test.file >>>> getfacl test.file >>> # file: test.file # owner: mpeters # group: wheel >>> owner@:rw-p--aARWcCos:------:allow >>> group@:r-----a-R-c--s:------:allow >>> everyone@:r-----a-R-c--s:------:allow >>>> setfacl -m user:nobody:rwx::allow test.file ls -al >>> total 4 drwxr-xr-x 2 mpeters wheel 3 Jun 12 15:32 . >>> drwxr-xr-x 5 root wheel 5 Jun 12 15:29 .. - -rw-r--r--+ 1 >>> mpeters wheel 0 Jun 12 15:32 test.file >>>> getfacl test.file >>> # file: test.file # owner: mpeters # group: wheel >>> user:nobody:rwx-----------:------:allow >>> owner@:rw-p--aARWcCos:------:allow >>> group@:r-----a-R-c--s:------:allow >>> everyone@:r-----a-R-c--s:------:allow >>>> vim test.file >>> (do some editing here) "test.file" 2 lines, 12 characters >>> written >>>> ls -al >>> total 4 drwxr-xr-x 2 mpeters wheel 3 Jun 12 15:35 . >>> drwxr-xr-x 5 root wheel 5 Jun 12 15:29 .. - -rw-r--r-- >>> 1 mpeters wheel 12 Jun 12 15:35 test.file >>>> getfacl test.file >>> # file: test.file # owner: mpeters # group: wheel >>> owner@:rw-p--aARWcCos:------:allow >>> group@:r-----a-R-c--s:------:allow >>> everyone@:r-----a-R-c--s:------:allow >>> >>> As you can see, the ACL for user nobody is gone. >>> >>> Is this behaviour intended? >> >> It is expected if vim replaced the original test.file with a >> modified file with the same name, instead of actually editing the >> original file directly. >> >> To confirm that this is happening you could truss vim or run "ls >> -i test.file" before and after using vim (this is probably less >> reliable, though). >> >> The ACLs shouldn't get lost if you really modify the original, >> for example with: >> >> echo blafasel >> test.file > > Also, take a look at what you have the aclmode property set to on > the ZFS file system. If you have it set to "discard" and if vim > makes a chmod(2) call on the original file, then the ACL entries > that do not represent the mode of the file will be discarded. > > -Andy > >> Fabian Thank you Andrew and Fabian. As discussed a little off list, the inheritance was the cuelprit, as already is stated in the FAQ: FAQ Q: Inheritance doesn't work the way I expect; access is denied while it shouldn't be. A: Set "aclmode=passthrough" and "aclinherit=passthrough" ZFS properties. For UFS, you're out of luck, I'm afraid; there is no way to change the behaviour there. Sorry for the noise. marc -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.17 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAk/YokYACgkQCnBgS+kUGEtHmQCfZdxsqM4kbdU8ug15/Kgs0wHf /mQAnilUmxAPnJokeNKpUVHLXtJqp45O =u3As -----END PGP SIGNATURE----- From owner-freebsd-fs@FreeBSD.ORG Wed Jun 13 14:24:23 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 933C71065679 for ; Wed, 13 Jun 2012 14:24:23 +0000 (UTC) (envelope-from prvs=151131130d=killing@multiplay.co.uk) Received: from mail1.multiplay.co.uk (mail1.multiplay.co.uk [85.236.96.23]) by mx1.freebsd.org (Postfix) with ESMTP id 2153E8FC19 for ; Wed, 13 Jun 2012 14:24:22 +0000 (UTC) X-Spam-Processed: mail1.multiplay.co.uk, Wed, 13 Jun 2012 15:23:53 +0100 X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on mail1.multiplay.co.uk X-Spam-Level: X-Spam-Status: No, score=-5.0 required=6.0 tests=USER_IN_WHITELIST shortcircuit=ham autolearn=disabled version=3.2.5 Received: from r2d2 ([188.220.16.49]) by mail1.multiplay.co.uk (mail1.multiplay.co.uk [85.236.96.23]) (MDaemon PRO v10.0.4) with ESMTP id md50020247582.msg for ; Wed, 13 Jun 2012 15:23:52 +0100 X-MDRemoteIP: 188.220.16.49 X-Return-Path: prvs=151131130d=killing@multiplay.co.uk X-Envelope-From: killing@multiplay.co.uk X-MDaemon-Deliver-To: freebsd-fs@freebsd.org Message-ID: From: "Steven Hartland" To: "Olivier Smedts" , "Irjohn Junus" References: Date: Wed, 13 Jun 2012 15:24:28 +0100 MIME-Version: 1.0 Content-Type: text/plain; format=flowed; charset="iso-8859-1"; reply-type=original Content-Transfer-Encoding: 7bit X-Priority: 3 X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook Express 6.00.2900.5931 X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.6157 Cc: freebsd-fs@freebsd.org Subject: Re: gpart add -a 4096 vs 4k X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 13 Jun 2012 14:24:23 -0000 ----- Original Message ----- 2012/6/13 Irjohn Junus : > Hello, > > Relatively new to FreeBSD and learning, I'm trying to partition my HDD and > align it to 4k sector. > > I do apologize if this has been answered before, I have Googled and read > gpart(8) man page to no joy. Can anyone please advice why gpart add '-a > 4096' doesn't yield the same result with '-a 4k'? Many thanks and captures > are below. Question: Do you actually want to partition? Or are you just trying to get it 4k aligned? Its my understanding, someone correct me if I'm wrong, that if you just want to create a zfs volume on a disk you can just use the raw disk instead of a partition slice and alignment just works. Its only if you want multiple slices and hence need to partition that you need to worry about alignment. Also worth noting that if your 4k disk is actually reporting as 512b sectors e.g. cat /var/run/dmesg.boot |grep sectors da0: 57241MB (117231408 512 byte sectors: 16H 63S/T 16383C) Then you can use gnop hack to fix this:- gnop create -S 4096 da0 zpool create mytank da0.nop zpool export mytank gnop destroy da0.nop zpool import mytank This will ensure the value of the zpool ashift is 12 for a 4k disk. You can check this with:- zdb | grep ashift In my testing this made 100MB/s performance increase for sequential writes of none random data on a Corsair Force 2 60GB ssd. Regards Steve ================================================ This e.mail is private and confidential between Multiplay (UK) Ltd. and the person or entity to whom it is addressed. In the event of misdirection, the recipient is prohibited from using, copying, printing or otherwise disseminating it or any information contained in it. In the event of misdirection, illegible or incomplete transmission please telephone +44 845 868 1337 or return the E.mail to postmaster@multiplay.co.uk. From owner-freebsd-fs@FreeBSD.ORG Wed Jun 13 16:10:08 2012 Return-Path: Delivered-To: freebsd-fs@hub.freebsd.org Received: from mx1.freebsd.org (unknown [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id BBF35106566C for ; Wed, 13 Jun 2012 16:10:08 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [69.147.83.40]) by mx1.freebsd.org (Postfix) with ESMTP id A12A58FC16 for ; Wed, 13 Jun 2012 16:10:08 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.5/8.14.5) with ESMTP id q5DGA8G3025058 for ; Wed, 13 Jun 2012 16:10:08 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.5/8.14.5/Submit) id q5DGA8GV025057; Wed, 13 Jun 2012 16:10:08 GMT (envelope-from gnats) Date: Wed, 13 Jun 2012 16:10:08 GMT Message-Id: <201206131610.q5DGA8GV025057@freefall.freebsd.org> To: freebsd-fs@FreeBSD.org From: Bryan Drewery Cc: Subject: Re: kern/167905: [zfs] zfs set canmount=on UNMOUNTS dataset X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Bryan Drewery List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 13 Jun 2012 16:10:08 -0000 The following reply was made to PR kern/167905; it has been noted by GNATS. From: Bryan Drewery To: vermaden Cc: bug-followup@FreeBSD.org, Pawel Jakub Dawidek , mm@freebsd.org Subject: Re: kern/167905: [zfs] zfs set canmount=on UNMOUNTS dataset Date: Wed, 13 Jun 2012 11:04:23 -0500 On 6/13/2012 1:37 AM, vermaden wrote: > at last I had some time to check Your work, but the patch did not applied to 9-STABLE @ r236934: It applies to HEAD and 9/stable for me. HEAD/cddl# patch -p1 -C < ../patch Hmm... Looks like a unified diff to me... The text leading up to this was: -------------------------- |--- cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c.orig 2012-06-12 00:10:11.000000000 -0500 |+++ cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c 2012-06-12 00:17:34.000000000 -0500 -------------------------- Patching file contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c using Plan A... Hunk #1 succeeded at 1485 (offset 18 lines). done -- Regards, Bryan Drewery bdrewery@freenode/EFNet From owner-freebsd-fs@FreeBSD.ORG Wed Jun 13 18:20:10 2012 Return-Path: Delivered-To: freebsd-fs@hub.freebsd.org Received: from mx1.freebsd.org (unknown [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 8808F106564A for ; Wed, 13 Jun 2012 18:20:10 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [69.147.83.40]) by mx1.freebsd.org (Postfix) with ESMTP id 71EE88FC12 for ; Wed, 13 Jun 2012 18:20:10 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.5/8.14.5) with ESMTP id q5DIKAow051208 for ; Wed, 13 Jun 2012 18:20:10 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.5/8.14.5/Submit) id q5DIKAVH051207; Wed, 13 Jun 2012 18:20:10 GMT (envelope-from gnats) Date: Wed, 13 Jun 2012 18:20:10 GMT Message-Id: <201206131820.q5DIKAVH051207@freefall.freebsd.org> To: freebsd-fs@FreeBSD.org From: Richard Yao Cc: Subject: Re: kern/161968: [zfs] [hang] renaming snapshot with -r including a zvol snapshot causes total ZFS freeze/lockup X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Richard Yao List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 13 Jun 2012 18:20:10 -0000 The following reply was made to PR kern/161968; it has been noted by GNATS. From: Richard Yao To: bug-followup@FreeBSD.org Cc: peter.maloney@brockmann-consult.de Subject: Re: kern/161968: [zfs] [hang] renaming snapshot with -r including a zvol snapshot causes total ZFS freeze/lockup Date: Wed, 13 Jun 2012 14:17:33 -0400 I tried to reproduce this issue after being contacted about it by Peter on freenode. I had to modify his script to destroy datasets individually, instead of recursively by running the following command: for i in $(zfs list -t snapshot -H -o name | grep testcrashsnap${current}); do zfs destroy $i; done; Otherwise, a "dataset is busy" failure occurs. This occurs on both FreeBSD and Linux. After doing that (and changing dataset=big to dataset=rpool), I was able to test his script in virtual machines running Gentoo FreeBSD 9-RELEASE and Gentoo Linux. I reproduced this issue on Gentoo FreeBSD 9.0-RELEASE. On the other hand, Gentoo Linux successfully completed 6570 iterations. This was with the ZFSOnLinux kernel modules. The code is available on github: https://github.com/zfsonlinux/zfs The actual code that I used to test was a patched version that I develop in a separate branch. You can find it here: https://github.com/ryao/zfs/tree/gentoo My current focus is on ZFS support in Gentoo Linux, but I would be happy to help my FreeBSD counterparts troubleshoot this. Please do not hesitate to contact me with questions. From owner-freebsd-fs@FreeBSD.ORG Wed Jun 13 20:41:16 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (unknown [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 339691065674 for ; Wed, 13 Jun 2012 20:41:16 +0000 (UTC) (envelope-from rsimmons0@gmail.com) Received: from mail-vc0-f182.google.com (mail-vc0-f182.google.com [209.85.220.182]) by mx1.freebsd.org (Postfix) with ESMTP id DEAB18FC15 for ; Wed, 13 Jun 2012 20:41:15 +0000 (UTC) Received: by vcbfy7 with SMTP id fy7so757938vcb.13 for ; Wed, 13 Jun 2012 13:41:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type; bh=lGee3KrJWCLAaNPisWR7Q6JjRMLRFu/Qm7P3LjpibxE=; b=MJ6jLNLlbnerMKmryTQsn9xMwDwub4xGtm0ZIhmQsxmYvzBfN1cp6I6HKV7e/rlotQ 599bb47MKLATcFPRSfFp14+rxk84OkF8n/9VAKxqQa6E6gDe6pjik/kxp8wPYe2lS4b9 +4Nf4dDYQWhOk0lf3eRtfrdxMHypUhJIJxAjW1NtdzioVeB2etSN+7MhyPEWcJJVg075 Yh8fhCtUO6QBlL/rgEoElK2RbWnGdap10dlRjqex9e3/8ulWcs8VzNTJUm5UvA1JPNTh RghYCGE9etrhsEqMgnG0uk5qXbmmSoIo/p9pvYtW2F+PgTAzZzljmaU7imgJDeongrzr QIMA== MIME-Version: 1.0 Received: by 10.52.69.110 with SMTP id d14mr3305051vdu.124.1339620074431; Wed, 13 Jun 2012 13:41:14 -0700 (PDT) Received: by 10.52.113.97 with HTTP; Wed, 13 Jun 2012 13:41:14 -0700 (PDT) In-Reply-To: References: Date: Wed, 13 Jun 2012 16:41:14 -0400 Message-ID: From: Robert Simmons To: freebsd-fs@freebsd.org Content-Type: text/plain; charset=ISO-8859-1 Subject: Re: gpart add -a 4096 vs 4k X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 13 Jun 2012 20:41:16 -0000 On Wed, Jun 13, 2012 at 10:24 AM, Steven Hartland wrote: > ----- Original Message ----- 2012/6/13 Irjohn Junus : > >> Hello, >> >> Relatively new to FreeBSD and learning, I'm trying to partition my HDD and >> align it to 4k sector. >> >> I do apologize if this has been answered before, I have Googled and read >> gpart(8) man page to no joy. Can anyone please advice why gpart add '-a >> 4096' doesn't yield the same result with '-a 4k'? Many thanks and captures >> are below. > > > > Question: Do you actually want to partition? Or are you just trying > to get it 4k aligned? > > Its my understanding, someone correct me if I'm wrong, that if you > just want to create a zfs volume on a disk you can just use the raw > disk instead of a partition slice and alignment just works. > > Its only if you want multiple slices and hence need to partition that > you need to worry about alignment. > > Also worth noting that if your 4k disk is actually reporting as 512b > sectors e.g. > cat /var/run/dmesg.boot |grep sectors > da0: 57241MB (117231408 512 byte sectors: 16H 63S/T 16383C) > > Then you can use gnop hack to fix this:- > gnop create -S 4096 da0 > zpool create mytank da0.nop > zpool export mytank > gnop destroy da0.nop > zpool import mytank > > This will ensure the value of the zpool ashift is 12 for a 4k disk. > You can check this with:- > zdb | grep ashift > > In my testing this made 100MB/s performance increase for sequential > writes of none random data on a Corsair Force 2 60GB ssd. Keep in mind that when you talk about alignment to 512b or to 4k, you are talking about HDD. When you enter the arena of SSD, you will need to look at the documentation from your manufacturer about what the proper alignment should be. It is related to the erase block boundaries rather than the size of sectors (SSD drives don't have sectors). This size also varies from manufacturer to manufacturer (some can be 1M some 2M). Some manufacturers try to keep this information secret too. OCZ is one of those, and even if you call their tech support they won't tell you. From owner-freebsd-fs@FreeBSD.ORG Thu Jun 14 06:11:14 2012 Return-Path: Delivered-To: freebsd-fs@hub.freebsd.org Received: from mx1.freebsd.org (unknown [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 171F41065695; Thu, 14 Jun 2012 06:11:14 +0000 (UTC) (envelope-from linimon@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [69.147.83.40]) by mx1.freebsd.org (Postfix) with ESMTP id DE3B28FC17; Thu, 14 Jun 2012 06:11:13 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.5/8.14.5) with ESMTP id q5E6BD1n041822; Thu, 14 Jun 2012 06:11:13 GMT (envelope-from linimon@freefall.freebsd.org) Received: (from linimon@localhost) by freefall.freebsd.org (8.14.5/8.14.5/Submit) id q5E6BD3D041813; Thu, 14 Jun 2012 06:11:13 GMT (envelope-from linimon) Date: Thu, 14 Jun 2012 06:11:13 GMT Message-Id: <201206140611.q5E6BD3D041813@freefall.freebsd.org> To: linimon@FreeBSD.org, freebsd-net@FreeBSD.org, freebsd-fs@FreeBSD.org From: linimon@FreeBSD.org Cc: Subject: Re: kern/169023: [libc] [patch] setfsent(), getfsent(), etc. leave /etc/fstab open after exec() X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 14 Jun 2012 06:11:14 -0000 Synopsis: [libc] [patch] setfsent(), getfsent(), etc. leave /etc/fstab open after exec() Responsible-Changed-From-To: freebsd-net->freebsd-fs Responsible-Changed-By: linimon Responsible-Changed-When: Thu Jun 14 06:10:49 UTC 2012 Responsible-Changed-Why: With bugmeister hat, try to assign this to fs@ to see if it can achieve some higher visibility. http://www.freebsd.org/cgi/query-pr.cgi?pr=169023 From owner-freebsd-fs@FreeBSD.ORG Thu Jun 14 09:02:09 2012 Return-Path: Delivered-To: freebsd-fs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 31C2E106566C; Thu, 14 Jun 2012 09:02:09 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [69.147.83.40]) by mx1.freebsd.org (Postfix) with ESMTP id 05F338FC0C; Thu, 14 Jun 2012 09:02:09 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.5/8.14.5) with ESMTP id q5E928o8018996; Thu, 14 Jun 2012 09:02:08 GMT (envelope-from kib@freefall.freebsd.org) Received: (from kib@localhost) by freefall.freebsd.org (8.14.5/8.14.5/Submit) id q5E928vE018987; Thu, 14 Jun 2012 09:02:08 GMT (envelope-from kib) Date: Thu, 14 Jun 2012 09:02:08 GMT Message-Id: <201206140902.q5E928vE018987@freefall.freebsd.org> To: kib@FreeBSD.org, freebsd-fs@FreeBSD.org, kib@FreeBSD.org From: kib@FreeBSD.org Cc: Subject: Re: kern/169023: [libc] [patch] setfsent(), getfsent(), etc. leave /etc/fstab open after exec() X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 14 Jun 2012 09:02:09 -0000 Synopsis: [libc] [patch] setfsent(), getfsent(), etc. leave /etc/fstab open after exec() Responsible-Changed-From-To: freebsd-fs->kib Responsible-Changed-By: kib Responsible-Changed-When: Thu Jun 14 09:01:53 UTC 2012 Responsible-Changed-Why: Take to see followup. http://www.freebsd.org/cgi/query-pr.cgi?pr=169023 From owner-freebsd-fs@FreeBSD.ORG Thu Jun 14 10:24:36 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (unknown [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id A70081065670 for ; Thu, 14 Jun 2012 10:24:36 +0000 (UTC) (envelope-from alexandr.kovalenko@gmail.com) Received: from mail-vc0-f182.google.com (mail-vc0-f182.google.com [209.85.220.182]) by mx1.freebsd.org (Postfix) with ESMTP id 344F18FC0A for ; Thu, 14 Jun 2012 10:24:36 +0000 (UTC) Received: by vcbfy7 with SMTP id fy7so1114991vcb.13 for ; Thu, 14 Jun 2012 03:24:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:date:message-id:subject:from:to:content-type; bh=Vy5c3i5a9D8HxWWFY5zszc6qYtU/riBrtmUBu8O8ZaE=; b=ExFsqbjhlvcdls3iWC83GV9zHzP/ISNu+iqWd6RKbviAc6pH1Zm5UYH49Tf8IO/taf /wIAj5Fo6Z8QGaFQqmx9aF0f8DpjhpWEmx5EqtIYRPfthbrjTzZ5eo+8CgxNEv9AOmRX NCe306ryHZxup6oeaONiIb0lZW70nI2Q/TRC33EB5BmZAlGMOk5SnTwzNmntpRhY1otH cB8fCvk8hhoF6FchYKQFQyaqgpGAjGhTy9rNj+nXEi6oBfiE2KqhQQu/ihcZ6DUKlNmz Wj1ofa7yT7Xzlm8xtsJyEXjJqreVrbSwQD9JBijDeZNKkipKy8CaAhAFFQYvsWsykB1d 7mKA== MIME-Version: 1.0 Received: by 10.220.240.147 with SMTP id la19mr671712vcb.47.1339669475357; Thu, 14 Jun 2012 03:24:35 -0700 (PDT) Received: by 10.220.226.6 with HTTP; Thu, 14 Jun 2012 03:24:35 -0700 (PDT) Date: Thu, 14 Jun 2012 13:24:35 +0300 Message-ID: From: Alexandr Kovalenko To: freebsd-fs@freebsd.org Content-Type: multipart/mixed; boundary=14dae9cfc16831f4c804c26c1bfb X-Content-Filtered-By: Mailman/MimeDel 2.1.5 Subject: zfs list -t snapshot slow X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 14 Jun 2012 10:24:36 -0000 --14dae9cfc16831f4c804c26c1bfb Content-Type: text/plain; charset=ISO-8859-1 Hello! I've noticed it takes pretty unreasonable amount of time to list snapshots: # time (zfs list -t snapshot 2>&1 > /dev/null) real 0m4.919s user 0m0.146s sys 0m0.716s # zfs list -t snapshot | wc -l 1838 kdump -f ktrace.out attached. Could anyone please advise what could cause this problem? -- Alexandr Kovalenko http://uafug.org.ua/ --14dae9cfc16831f4c804c26c1bfb-- From owner-freebsd-fs@FreeBSD.ORG Thu Jun 14 10:30:28 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (unknown [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 2CA891065670 for ; Thu, 14 Jun 2012 10:30:28 +0000 (UTC) (envelope-from devgs@ukr.net) Received: from ffe15.ukr.net (ffe15.ukr.net [195.214.192.50]) by mx1.freebsd.org (Postfix) with ESMTP id CD01B8FC1A for ; Thu, 14 Jun 2012 10:30:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=ukr.net; s=ffe; h=Date:Message-Id:From:To:Subject:Content-Type:Content-Transfer-Encoding:MIME-Version; bh=sBCOZoOVOMF/48+T1KFKLSPumdhhmGf7fEgt5LlkuZc=; b=tQu5pH+Dyp3D1B1F/19//pvmtZUv2lZ5PMXqtmjNVCaneyyPjbAHjQYI0TAAJyRGCb6xIupcx97o1uHOfZCmmIUYTSlol4Mm+pvWtP8p5sramT48gsxoHkhiLddLy0BpdA/Uz7bEBZIUnGQTEJShoy+Hkuzqd+cfEKWipnELwEE=; Received: from mail by ffe15.ukr.net with local ID 1Sf7Jk-000OqM-Lu for freebsd-fs@freebsd.org; Thu, 14 Jun 2012 13:30:20 +0300 MIME-Version: 1.0 To: freebsd-fs@freebsd.org From: "Pavlo" X-Mailer: freemail.ukr.net 4.0 X-Originating-Ip: [212.42.94.154] Message-Id: <91943.1339669820.1305529125424791552@ffe15.ukr.net> X-Browser: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:13.0) Gecko/20100101 Firefox/13.0 Date: Thu, 14 Jun 2012 13:30:20 +0300 Content-Type: text/plain; charset="windows-1251" Content-Transfer-Encoding: binary Content-Disposition: inline X-Content-Filtered-By: Mailman/MimeDel 2.1.5 Subject: mmap() incoherency on hi I/O load (FS is zfs) X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 14 Jun 2012 10:30:28 -0000 There's a case when some parts of files that are mapped and then modified getting corrupted. By corrupted I mean some data is ok (one that was written using write()/pwrite()) but some looks like it never existed. Like it was some time in buffers, when several processes simultaneously (of course access was synchronised) used shared pages and reported it's existence. But after time pass they (processes) screamed that it is now lost. Only part of data written with pwrite() was there. Everything that was written via mmap() is zero. So as I said it occurs on hi I/O busyness. When in background 4+ processes do indexing of huge ammount of data. Also I want to note, it never occurred in the life of our project while we used mmap() under same I/O stress conditions when mapping was done for a whole file of just a part(header) starting from a beginning of a file. First time we used mapping of individual pages, just to save RAM, and this popped up. Solution for this problem is msync() before any munmap(). But man says: The msync() system call is usually not needed since BSD implements a coherent file system buffer cache. However, it may be used to associate dirty VM pages with file system buffers and thus cause them to be flushed to physical media sooner rather than later. Any thoughts? Thanks. From owner-freebsd-fs@FreeBSD.ORG Thu Jun 14 10:37:17 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 8A629106564A for ; Thu, 14 Jun 2012 10:37:17 +0000 (UTC) (envelope-from c.kworr@gmail.com) Received: from mail-bk0-f54.google.com (mail-bk0-f54.google.com [209.85.214.54]) by mx1.freebsd.org (Postfix) with ESMTP id 136FA8FC08 for ; Thu, 14 Jun 2012 10:37:16 +0000 (UTC) Received: by bkvi18 with SMTP id i18so1620276bkv.13 for ; Thu, 14 Jun 2012 03:37:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=message-id:date:from:user-agent:mime-version:to:cc:subject :references:in-reply-to:content-type:content-transfer-encoding; bh=8GPIA+8oGFaD7/4izZvPNWNdT+GezzlEMuo2vCastdY=; b=TMrf4xagDwHkl4ZrOZg/UcF9AoI85hXD2olZm47qnlBCdZ3P+jXwthgkEOB7/tQd+Z spWkxtGKra3hclLHKjDSeuf0AliAmakCxXICop3u5ISPESeoUs6d5xemzM+8YSp3eAor E6Kw3zHBrfIaKwMLrwLiopVD7KIM/d/tBG7V2DMok8OYaE/hHDWkvxR33NlAlJ2YDHW6 dJE4CUGRrDsm02gH2E5ljaTXy/IRiE6UX02O77Jn6Fvc4+UUDzc8ZzTAmxisdP+Nrsv6 1QgxwDJgdWhSCVlQahyFRyrwRm4DevebpBPTZx6qGEUBBL6m8uvpCv3nPdgqhzz5+Z3d +F2w== Received: by 10.205.139.81 with SMTP id iv17mr675890bkc.118.1339670236129; Thu, 14 Jun 2012 03:37:16 -0700 (PDT) Received: from green.tandem.local (utwig.xim.bz. [91.216.237.46]) by mx.google.com with ESMTPS id n17sm6081650bkw.5.2012.06.14.03.37.11 (version=SSLv3 cipher=OTHER); Thu, 14 Jun 2012 03:37:12 -0700 (PDT) Message-ID: <4FD9BED5.7050901@gmail.com> Date: Thu, 14 Jun 2012 13:37:09 +0300 From: Volodymyr Kostyrko User-Agent: Mozilla/5.0 (X11; FreeBSD amd64; rv:12.0) Gecko/20120605 Firefox/12.0 SeaMonkey/2.9.1 MIME-Version: 1.0 To: Alexandr Kovalenko References: In-Reply-To: Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Cc: freebsd-fs@freebsd.org Subject: Re: zfs list -t snapshot slow X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 14 Jun 2012 10:37:17 -0000 Alexandr Kovalenko wrote: > Hello! > > I've noticed it takes pretty unreasonable amount of time to list snapshots: > > # time (zfs list -t snapshot 2>&1> /dev/null) > > real 0m4.919s > user 0m0.146s > sys 0m0.716s > > # zfs list -t snapshot | wc -l > 1838 > > kdump -f ktrace.out attached. Attachment automagically stripped. > Could anyone please advise what could cause this problem? What version are you running? There was move about that after 9.0 Release, patches should be in 8.3 and 9-STABLE. -- Sphinx of black quartz judge my vow. From owner-freebsd-fs@FreeBSD.ORG Thu Jun 14 10:45:21 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (unknown [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 174F71065672 for ; Thu, 14 Jun 2012 10:45:21 +0000 (UTC) (envelope-from mm@FreeBSD.org) Received: from mail.vx.sk (mail.vx.sk [176.9.45.25]) by mx1.freebsd.org (Postfix) with ESMTP id 84F1F8FC18 for ; Thu, 14 Jun 2012 10:45:20 +0000 (UTC) Received: from core.vx.sk (localhost [127.0.0.2]) by mail.vx.sk (Postfix) with ESMTP id 951C97BA1; Thu, 14 Jun 2012 12:45:19 +0200 (CEST) X-Virus-Scanned: amavisd-new at mail.vx.sk Received: from mail.vx.sk by core.vx.sk (amavisd-new, unix socket) with LMTP id vHIaj4_hrQG2; Thu, 14 Jun 2012 12:45:14 +0200 (CEST) Received: from [10.0.3.3] (188-167-66-148.dynamic.chello.sk [188.167.66.148]) by mail.vx.sk (Postfix) with ESMTPSA id 294047B9B; Thu, 14 Jun 2012 12:45:14 +0200 (CEST) Message-ID: <4FD9C0B9.5050507@FreeBSD.org> Date: Thu, 14 Jun 2012 12:45:13 +0200 From: Martin Matuska User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20120428 Thunderbird/12.0.1 MIME-Version: 1.0 To: Alexandr Kovalenko References: In-Reply-To: X-Enigmail-Version: 1.4.2 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit Cc: freebsd-fs@freebsd.org Subject: Re: zfs list -t snapshot slow X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 14 Jun 2012 10:45:21 -0000 Hi Alexandr, this slowdown is known, as for fetching each snapshot its metadata are to be fetched. There was a speedup to this operation, but it affects only name-sorted output, you need to issue "-o name -s name" to your zfs list command. More information: http://svnweb.freebsd.org/base?view=revision&revision=230438 This change has been integrated into the tree on: HEAD: r230438 (2012-01-21) 9-STABLE: r231946 (2012-02-20) 8-STABLE: r233862 (2012-04-04) On 14. 6. 2012 12:24, Alexandr Kovalenko wrote: > Hello! > > I've noticed it takes pretty unreasonable amount of time to list snapshots: > > # time (zfs list -t snapshot 2>&1 > /dev/null) > > real 0m4.919s > user 0m0.146s > sys 0m0.716s > > # zfs list -t snapshot | wc -l > 1838 > > kdump -f ktrace.out attached. > > Could anyone please advise what could cause this problem? -- Martin Matuska FreeBSD committer http://blog.vx.sk From owner-freebsd-fs@FreeBSD.ORG Thu Jun 14 11:32:42 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (unknown [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id E03D91065672 for ; Thu, 14 Jun 2012 11:32:42 +0000 (UTC) (envelope-from rmacklem@uoguelph.ca) Received: from esa-scalar.mail.uoguelph.ca (esa-scalar.mail.uoguelph.ca [66.199.40.18]) by mx1.freebsd.org (Postfix) with ESMTP id 7CAC18FC08 for ; Thu, 14 Jun 2012 11:32:42 +0000 (UTC) Received: from zcs3.mail.uoguelph.ca (new.mail.uoguelph.ca [131.104.93.37]) by esa-scalar.mail.uoguelph.ca (8.14.1/8.14.1) with ESMTP id q5EBWa2B019861; Thu, 14 Jun 2012 07:32:36 -0400 Received: from zcs3.mail.uoguelph.ca (localhost.localdomain [127.0.0.1]) by zcs3.mail.uoguelph.ca (Postfix) with ESMTP id 3BF66B406E; Thu, 14 Jun 2012 07:32:36 -0400 (EDT) Date: Thu, 14 Jun 2012 07:32:36 -0400 (EDT) From: Rick Macklem To: Pavlo Message-ID: <893489718.1762311.1339673556220.JavaMail.root@erie.cs.uoguelph.ca> In-Reply-To: <91943.1339669820.1305529125424791552@ffe15.ukr.net> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-Originating-IP: [172.17.91.201] X-Mailer: Zimbra 6.0.10_GA_2692 (ZimbraWebClient - FF3.0 (Win)/6.0.10_GA_2692) Cc: freebsd-fs@freebsd.org Subject: Re: mmap() incoherency on hi I/O load (FS is zfs) X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 14 Jun 2012 11:32:43 -0000 Pavlo wrote: > There's a case when some parts of files that are mapped and then > modified getting corrupted. By corrupted I mean some data is ok (one > that > was written using write()/pwrite()) but some looks like it never > existed. > Like it was some time in buffers, when several processes > simultaneously > (of course access was synchronised) used shared pages and reported > it's > existence. But after time pass they (processes) screamed that it is > now > lost. Only part of data written with pwrite() was there. Everything > that > was written via mmap() is zero. > > So as I said it occurs on hi I/O busyness. When in background 4+ > processes do indexing of huge ammount of data. Also I want to note, it > never occurred in the life of our project while we used mmap() under > same I/O stress conditions when mapping was done for a whole file of > just > a part(header) starting from a beginning of a file. First time we used > mapping of individual pages, just to save RAM, and this popped up. > > Solution for this problem is msync() before any munmap(). But man > says: > > The msync() system call is usually not needed since BSD implements a > coherent file system buffer cache. However, it may be used to > associate > dirty VM pages with file system buffers and thus cause them to be > flushed > to physical media sooner rather than later. > > Any thoughts? Thanks. > With a recent kernel from head, I am seeing dirty mmap'd pages being written quite late for the NFSv4 client. Even after the NFS client VOP_RECLAIM() has been called, it seems. I didn't observe this behaviour in a kernel from head in March. (I don't know enough about the vm/mmap area to know if this is correct behaviour or not?) I thought I'd mention this, since you didn't say how recent a kernel you were running and thought it might be caused by the same change? Sorry I can't help more, rick > _______________________________________________ > freebsd-fs@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-fs > To unsubscribe, send any mail to "freebsd-fs-unsubscribe@freebsd.org" From owner-freebsd-fs@FreeBSD.ORG Thu Jun 14 12:04:58 2012 Return-Path: Delivered-To: freebsd-fs@hub.freebsd.org Received: from mx1.freebsd.org (unknown [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 3B8AA1065672; Thu, 14 Jun 2012 12:04:58 +0000 (UTC) (envelope-from mm@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [69.147.83.40]) by mx1.freebsd.org (Postfix) with ESMTP id 11DE68FC1D; Thu, 14 Jun 2012 12:04:58 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.5/8.14.5) with ESMTP id q5EC4v9X094767; Thu, 14 Jun 2012 12:04:57 GMT (envelope-from mm@freefall.freebsd.org) Received: (from mm@localhost) by freefall.freebsd.org (8.14.5/8.14.5/Submit) id q5EC4vp9094763; Thu, 14 Jun 2012 12:04:57 GMT (envelope-from mm) Date: Thu, 14 Jun 2012 12:04:57 GMT Message-Id: <201206141204.q5EC4vp9094763@freefall.freebsd.org> To: mm@FreeBSD.org, freebsd-fs@FreeBSD.org, mm@FreeBSD.org From: mm@FreeBSD.org Cc: Subject: Re: kern/167905: [zfs] zfs set canmount=on UNMOUNTS dataset X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 14 Jun 2012 12:04:58 -0000 Synopsis: [zfs] zfs set canmount=on UNMOUNTS dataset Responsible-Changed-From-To: freebsd-fs->mm Responsible-Changed-By: mm Responsible-Changed-When: Thu Jun 14 12:04:57 UTC 2012 Responsible-Changed-Why: I'll take it. http://www.freebsd.org/cgi/query-pr.cgi?pr=167905 From owner-freebsd-fs@FreeBSD.ORG Thu Jun 14 12:10:56 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (unknown [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id E4957106567A for ; Thu, 14 Jun 2012 12:10:56 +0000 (UTC) (envelope-from devgs@ukr.net) Received: from ffe5.ukr.net (ffe5.ukr.net [195.214.192.21]) by mx1.freebsd.org (Postfix) with ESMTP id 72FBC8FC0C for ; Thu, 14 Jun 2012 12:10:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=ukr.net; s=ffe; h=Date:Message-Id:From:To:References:In-Reply-To:Subject:Cc:Content-Type:Content-Transfer-Encoding:MIME-Version; bh=fKfnF6OdK7v+hs4ncOQfcSoPQsIwf/GL+hy+2Q9mHv4=; b=TbyuaCrxYdgzm/+espkS5T1rqSyJMWluIIYgE2T0Y+A8nZwJa8lx5GgxOyy+NsKDzz/AVxjFUwOonQOI7h/qLpPntgyFkOwDcee0Gg2PGWLFDxl/UWofwUTCFDqdajtRnWS6jFuhJYZ/Vzkq1A0CXmfG8Zpu3/LfYs6hRBZ35/c=; Received: from mail by ffe5.ukr.net with local ID 1Sf8ZZ-0005UR-59 ; Thu, 14 Jun 2012 14:50:45 +0300 MIME-Version: 1.0 In-Reply-To: <893489718.1762311.1339673556220.JavaMail.root@erie.cs.uoguelph.ca> References: <893489718.1762311.1339673556220.JavaMail.root@erie.cs.uoguelph.ca> To: "Rick Macklem" From: "Pavlo" X-Mailer: freemail.ukr.net 4.0 X-Originating-Ip: [212.42.94.154] Message-Id: <14119.1339674645.325291171772956672@ffe5.ukr.net> X-Browser: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:13.0) Gecko/20100101 Firefox/13.0 Date: Thu, 14 Jun 2012 14:50:45 +0300 Content-Type: text/plain; charset="windows-1251" Content-Transfer-Encoding: binary Content-Disposition: inline X-Content-Filtered-By: Mailman/MimeDel 2.1.5 Cc: freebsd-fs@freebsd.org Subject: Re: mmap() incoherency on hi I/O load (FS is zfs) X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 14 Jun 2012 12:10:57 -0000 > Pavlo wrote: > There's a case when some parts of files that are mapped and then > modified getting corrupted. By corrupted I mean some data is ok (one > that > was written using write()/pwrite()) but some looks like it never > existed. > Like it was some time in buffers, when several processes > simultaneously > (of course access was synchronised) used shared pages and reported > it's > existence. But after time pass they (processes) screamed that it is > now > lost. Only part of data written with pwrite() was there. Everything > that > was written via mmap() is zero. > > So as I said it occurs on hi I/O busyness. When in background 4+ > processes do indexing of huge ammount of data. Also I want to note, it > never occurred in the life of our project while we used mmap() under > same I/O stress conditions when mapping was done for a whole file of > just > a part(header) starting from a beginning of a file. First time we used > mapping of individual pages, just to save RAM, and this popped up. > > Solution for this problem is msync() before any munmap(). But man > says: > > The msync() system call is usually not needed since BSD implements a > coherent file system buffer cache. However, it may be used to > associate > dirty VM pages with file system buffers and thus cause them to be > flushed > to physical media sooner rather than later. > > Any thoughts? Thanks. > With a recent kernel from head, I am seeing dirty mmap'd pages being written quite late for the NFSv4 client. Even after the NFS client VOP_RECLAIM() has been called, it seems. I didn't observe this behaviour in a kernel from head in March. (I don't know enough about the vm/mmap area to know if this is correct behaviour or not?) I thought I'd mention this, since you didn't say how recent a kernel you were running and thought it might be caused by the same change? Sorry I can't help more, rick > _______________________________________________ > freebsd-fs@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-fs> To unsubscribe, send any mail to "freebsd-fs-unsubscribe@freebsd.org" > Thanks for reply, Rick! Yes, we have pretty old kernel: # uname -a FreeBSD mpop-zebra-k1.ukr.net 8.2-STABLE FreeBSD 8.2-STABLE #9: Wed Jan 25 11:28:55 EET 2012 I just posted my observation here to point out possible problem that could still exist. From owner-freebsd-fs@FreeBSD.ORG Thu Jun 14 12:25:00 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (unknown [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 1B7F41065674 for ; Thu, 14 Jun 2012 12:25:00 +0000 (UTC) (envelope-from kostikbel@gmail.com) Received: from mail.zoral.com.ua (mx0.zoral.com.ua [91.193.166.200]) by mx1.freebsd.org (Postfix) with ESMTP id A88BF8FC12 for ; Thu, 14 Jun 2012 12:24:59 +0000 (UTC) Received: from skuns.kiev.zoral.com.ua (localhost [127.0.0.1]) by mail.zoral.com.ua (8.14.2/8.14.2) with ESMTP id q5ECOu3l060941; Thu, 14 Jun 2012 15:24:56 +0300 (EEST) (envelope-from kostikbel@gmail.com) Received: from deviant.kiev.zoral.com.ua (kostik@localhost [127.0.0.1]) by deviant.kiev.zoral.com.ua (8.14.5/8.14.5) with ESMTP id q5ECOuoY032355; Thu, 14 Jun 2012 15:24:56 +0300 (EEST) (envelope-from kostikbel@gmail.com) Received: (from kostik@localhost) by deviant.kiev.zoral.com.ua (8.14.5/8.14.5/Submit) id q5ECOuIb032354; Thu, 14 Jun 2012 15:24:56 +0300 (EEST) (envelope-from kostikbel@gmail.com) X-Authentication-Warning: deviant.kiev.zoral.com.ua: kostik set sender to kostikbel@gmail.com using -f Date: Thu, 14 Jun 2012 15:24:56 +0300 From: Konstantin Belousov To: Rick Macklem Message-ID: <20120614122456.GZ2337@deviant.kiev.zoral.com.ua> References: <91943.1339669820.1305529125424791552@ffe15.ukr.net> <893489718.1762311.1339673556220.JavaMail.root@erie.cs.uoguelph.ca> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="tpXmNJJzF/fVXUEg" Content-Disposition: inline In-Reply-To: <893489718.1762311.1339673556220.JavaMail.root@erie.cs.uoguelph.ca> User-Agent: Mutt/1.4.2.3i X-Virus-Scanned: clamav-milter 0.95.2 at skuns.kiev.zoral.com.ua X-Virus-Status: Clean X-Spam-Status: No, score=-4.0 required=5.0 tests=ALL_TRUSTED,AWL,BAYES_00 autolearn=ham version=3.2.5 X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on skuns.kiev.zoral.com.ua Cc: freebsd-fs@freebsd.org, Pavlo Subject: Re: mmap() incoherency on hi I/O load (FS is zfs) X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 14 Jun 2012 12:25:00 -0000 --tpXmNJJzF/fVXUEg Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Thu, Jun 14, 2012 at 07:32:36AM -0400, Rick Macklem wrote: > Pavlo wrote: > > There's a case when some parts of files that are mapped and then > > modified getting corrupted. By corrupted I mean some data is ok (one > > that > > was written using write()/pwrite()) but some looks like it never > > existed. > > Like it was some time in buffers, when several processes > > simultaneously > > (of course access was synchronised) used shared pages and reported > > it's > > existence. But after time pass they (processes) screamed that it is > > now > > lost. Only part of data written with pwrite() was there. Everything > > that > > was written via mmap() is zero. > >=20 > > So as I said it occurs on hi I/O busyness. When in background 4+ > > processes do indexing of huge ammount of data. Also I want to note, it > > never occurred in the life of our project while we used mmap() under > > same I/O stress conditions when mapping was done for a whole file of > > just > > a part(header) starting from a beginning of a file. First time we used > > mapping of individual pages, just to save RAM, and this popped up. > >=20 > > Solution for this problem is msync() before any munmap(). But man > > says: > >=20 > > The msync() system call is usually not needed since BSD implements a > > coherent file system buffer cache. However, it may be used to > > associate > > dirty VM pages with file system buffers and thus cause them to be > > flushed > > to physical media sooner rather than later. > >=20 > > Any thoughts? Thanks. > >=20 > With a recent kernel from head, I am seeing dirty mmap'd pages being writ= ten > quite late for the NFSv4 client. Even after the NFS client VOP_RECLAIM() = has > been called, it seems. I didn't observe this behaviour in a kernel from > head in March. (I don't know enough about the vm/mmap area to know if this > is correct behaviour or not?) >=20 > I thought I'd mention this, since you didn't say how recent a kernel you > were running and thought it might be caused by the same change? Can you, please, comment more on this ? How is this possible at all ? Could you please show at least a backtrace for the moment when a write request is made for the page which belong to already reclaimed vnode ? --tpXmNJJzF/fVXUEg Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (FreeBSD) iEYEARECAAYFAk/Z2BgACgkQC3+MBN1Mb4iu4QCgolZfcId5IWvExU1Bmo/BsQcl itoAniEGa0b85JgpCdPQEaVDU7gMVYju =h/2C -----END PGP SIGNATURE----- --tpXmNJJzF/fVXUEg-- From owner-freebsd-fs@FreeBSD.ORG Thu Jun 14 14:16:43 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (unknown [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 8D003106566B for ; Thu, 14 Jun 2012 14:16:43 +0000 (UTC) (envelope-from i.junus@gmail.com) Received: from mail-wi0-f172.google.com (mail-wi0-f172.google.com [209.85.212.172]) by mx1.freebsd.org (Postfix) with ESMTP id 951228FC08 for ; Thu, 14 Jun 2012 14:16:42 +0000 (UTC) Received: by wibhj8 with SMTP id hj8so5312673wib.13 for ; Thu, 14 Jun 2012 07:16:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=wNDTwOh7w8YOr+JzH5fnx+8E2YR3Z/+FitMLBIysb7E=; b=O0PqqNGeaMjGdelNspyPOXqTcg+8KwvvbYr0DB93PMYLud7zylS2nBziYUwVdnj6/A 10LnvkbIFhiP96LGpw8Zp2stXW7qM8xGSiClwRvizQcCN7Hojw5WDGrxk1KxylfuBeJx H91teKwVj+/30IeuCfJ7w18b/wcgeLNxX4kLmuaX3Fp0EVk9+ISP1op9M6ZWPiWMhvLj corTV1mQjreMcyx60WKLDwFL/+PltMI+h84+Yk4snTLmYEkbOKBIVQZZ7t2ELUdINKD2 MDr2OTvTAhN44Nqqz9AD8mIHjWxyzPLPiqTceBW+mNnQ94wOuwAsAv3TPgxd1P1sPATr 183A== MIME-Version: 1.0 Received: by 10.180.8.69 with SMTP id p5mr47076161wia.17.1339683396291; Thu, 14 Jun 2012 07:16:36 -0700 (PDT) Received: by 10.194.33.42 with HTTP; Thu, 14 Jun 2012 07:16:35 -0700 (PDT) In-Reply-To: References: Date: Thu, 14 Jun 2012 22:16:35 +0800 Message-ID: From: Irjohn Junus To: Robert Simmons Content-Type: multipart/related; boundary=f46d044283b6f28ae304c26f5825 X-Content-Filtered-By: Mailman/MimeDel 2.1.5 Cc: freebsd-fs@freebsd.org Subject: Re: gpart add -a 4096 vs 4k X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 14 Jun 2012 14:16:43 -0000 --f46d044283b6f28ae304c26f5825 Content-Type: text/plain; charset=ISO-8859-1 Thank you Robert and Steve. I'm building a ZFS pool (striped mirrors, boot and ZIL on an SSD - perhaps another SSD for L2ARC but this is later) with consumer grade spindle disks. Choice was either Seagate's 4K Barracuda 7200.14 or Hitachi's 512B 7K3000, both 2TB capacity. I decided to go with Hitachi because here where I live it comes with 3yr warranty vs 2yr for Seagate, although the Hitachis are 20% pricier at current price. Also, I have had good experience with Hitachi; my 1st generation Apple Time Capsule is still going strong after so many years (it has a 500GB Hitachi). The challenge is, I need to future-proof my ZFS pool built on these (last of high capacity 512B spindle disk?) Hitachis in case I need to replace any with 4K drive in the near future. Thus all these headaches about raw vs GPTed, 4K partition alignment, start sector, ashift value etc etc etc while at the same time balancing read/ write performance. I did some preliminary tests on a couple of mirrored Hitachis with dd and bonnie++ and it's interesting that the best read/ write balance at ashift=12 is to have these Hitachis GPTed and aligned with -a 4k. I'm attaching a table below for everyone's comment (PNG file, please let me know if you can't view it). [image: Inline image 1] System is Intel DH61WW mainboard with i3-2120 and 16GB 1333MHz DRAM. Boot SSD is Intel 320 120GB with the mainboard, Hitachis with an IBM M1015 flashed to LSI 9211-8i IT firmware. Thanks, Irjohn On Thu, Jun 14, 2012 at 4:41 AM, Robert Simmons wrote: > On Wed, Jun 13, 2012 at 10:24 AM, Steven Hartland > wrote: > > ----- Original Message ----- 2012/6/13 Irjohn Junus : > > > >> Hello, > >> > >> Relatively new to FreeBSD and learning, I'm trying to partition my HDD > and > >> align it to 4k sector. > >> > >> I do apologize if this has been answered before, I have Googled and read > >> gpart(8) man page to no joy. Can anyone please advice why gpart add '-a > >> 4096' doesn't yield the same result with '-a 4k'? Many thanks and > captures > >> are below. > > > > > > > > Question: Do you actually want to partition? Or are you just trying > > to get it 4k aligned? > > > > Its my understanding, someone correct me if I'm wrong, that if you > > just want to create a zfs volume on a disk you can just use the raw > > disk instead of a partition slice and alignment just works. > > > > Its only if you want multiple slices and hence need to partition that > > you need to worry about alignment. > > > > Also worth noting that if your 4k disk is actually reporting as 512b > > sectors e.g. > > cat /var/run/dmesg.boot |grep sectors > > da0: 57241MB (117231408 512 byte sectors: 16H 63S/T 16383C) > > > > Then you can use gnop hack to fix this:- > > gnop create -S 4096 da0 > > zpool create mytank da0.nop > > zpool export mytank > > gnop destroy da0.nop > > zpool import mytank > > > > This will ensure the value of the zpool ashift is 12 for a 4k disk. > > You can check this with:- > > zdb | grep ashift > > > > In my testing this made 100MB/s performance increase for sequential > > writes of none random data on a Corsair Force 2 60GB ssd. > > Keep in mind that when you talk about alignment to 512b or to 4k, you > are talking about HDD. When you enter the arena of SSD, you will need > to look at the documentation from your manufacturer about what the > proper alignment should be. It is related to the erase block > boundaries rather than the size of sectors (SSD drives don't have > sectors). This size also varies from manufacturer to manufacturer > (some can be 1M some 2M). Some manufacturers try to keep this > information secret too. OCZ is one of those, and even if you call > their tech support they won't tell you. > _______________________________________________ > freebsd-fs@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-fs > To unsubscribe, send any mail to "freebsd-fs-unsubscribe@freebsd.org" > --f46d044283b6f28ae304c26f5825-- From owner-freebsd-fs@FreeBSD.ORG Fri Jun 15 15:34:52 2012 Return-Path: Delivered-To: freebsd-fs@freebsd.org Received: from mx1.freebsd.org (unknown [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id E1B561065670 for ; Fri, 15 Jun 2012 15:34:52 +0000 (UTC) (envelope-from rmacklem@uoguelph.ca) Received: from esa-scalar.mail.uoguelph.ca (esa-scalar.mail.uoguelph.ca [66.199.40.18]) by mx1.freebsd.org (Postfix) with ESMTP id 76E938FC18 for ; Fri, 15 Jun 2012 15:34:52 +0000 (UTC) Received: from zcs3.mail.uoguelph.ca (new.mail.uoguelph.ca [131.104.93.37]) by esa-scalar.mail.uoguelph.ca (8.14.1/8.14.1) with ESMTP id q5FFYmk5017695; Fri, 15 Jun 2012 11:34:48 -0400 Received: from zcs3.mail.uoguelph.ca (localhost.localdomain [127.0.0.1]) by zcs3.mail.uoguelph.ca (Postfix) with ESMTP id 0760FB4047; Fri, 15 Jun 2012 11:34:48 -0400 (EDT) Date: Fri, 15 Jun 2012 11:34:48 -0400 (EDT) From: Rick Macklem To: Konstantin Belousov Message-ID: <1116727909.1836239.1339774488001.JavaMail.root@erie.cs.uoguelph.ca> In-Reply-To: <20120614122456.GZ2337@deviant.kiev.zoral.com.ua> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-Originating-IP: [172.17.91.202] X-Mailer: Zimbra 6.0.10_GA_2692 (ZimbraWebClient - FF3.0 (Win)/6.0.10_GA_2692) Cc: freebsd-fs@freebsd.org, Pavlo Subject: Re: mmap() incoherency on hi I/O load (FS is zfs) X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 15 Jun 2012 15:34:53 -0000 Kostik wrote: > On Thu, Jun 14, 2012 at 07:32:36AM -0400, Rick Macklem wrote: > > Pavlo wrote: > > > There's a case when some parts of files that are mapped and then > > > modified getting corrupted. By corrupted I mean some data is ok > > > (one > > > that > > > was written using write()/pwrite()) but some looks like it never > > > existed. > > > Like it was some time in buffers, when several processes > > > simultaneously > > > (of course access was synchronised) used shared pages and reported > > > it's > > > existence. But after time pass they (processes) screamed that it > > > is > > > now > > > lost. Only part of data written with pwrite() was there. > > > Everything > > > that > > > was written via mmap() is zero. > > > > > > So as I said it occurs on hi I/O busyness. When in background 4+ > > > processes do indexing of huge ammount of data. Also I want to > > > note, it > > > never occurred in the life of our project while we used mmap() > > > under > > > same I/O stress conditions when mapping was done for a whole file > > > of > > > just > > > a part(header) starting from a beginning of a file. First time we > > > used > > > mapping of individual pages, just to save RAM, and this popped up. > > > > > > Solution for this problem is msync() before any munmap(). But man > > > says: > > > > > > The msync() system call is usually not needed since BSD implements > > > a > > > coherent file system buffer cache. However, it may be used to > > > associate > > > dirty VM pages with file system buffers and thus cause them to be > > > flushed > > > to physical media sooner rather than later. > > > > > > Any thoughts? Thanks. > > > > > With a recent kernel from head, I am seeing dirty mmap'd pages being > > written > > quite late for the NFSv4 client. Even after the NFS client > > VOP_RECLAIM() has > > been called, it seems. I didn't observe this behaviour in a kernel > > from > > head in March. (I don't know enough about the vm/mmap area to know > > if this > > is correct behaviour or not?) > > > > I thought I'd mention this, since you didn't say how recent a kernel > > you > > were running and thought it might be caused by the same change? > Can you, please, comment more on this ? > How is this possible at all ? > > Could you please show at least a backtrace for the moment when a write > request is made for the page which belong to already reclaimed vnode ? After some off list discussion, it was determined that my problem was doing nfsrpc_close() before vnode_destroy_object() in the NFSv4 client's VOP_RECLAIM(). This is an NFSv4 specific bug and wouldn't be related to the above issue. Sorry about the noise, rick