<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://xfs.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Dgc</id>
	<title>xfs.org - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://xfs.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Dgc"/>
	<link rel="alternate" type="text/html" href="https://xfs.org/index.php/Special:Contributions/Dgc"/>
	<updated>2026-04-20T08:50:58Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.42.3</generator>
	<entry>
		<id>https://xfs.org/index.php?title=Getting_the_latest_source_code&amp;diff=3002</id>
		<title>Getting the latest source code</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=Getting_the_latest_source_code&amp;diff=3002"/>
		<updated>2016-10-18T23:43:06Z</updated>

		<summary type="html">&lt;p&gt;Dgc: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== &amp;lt;font face=&amp;quot;ARIAL NARROW,HELVETICA&amp;quot;&amp;gt; XFS Released/Stable source &amp;lt;/font&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Note: as of September 2016, the XFS project is moving away from oss.sgi.com infrastructure. As we move to other infrastructure the links below will be updated to point to the new locations.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Mainline kernels&#039;&#039;&#039;&lt;br /&gt;
:XFS has been maintained in the official Linux kernel [http://www.kernel.org/ kernel trees] starting with [http://lkml.org/lkml/2003/12/8/35 Linux 2.4] and is frequently updated with the latest stable fixes and features from the XFS development team.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Vendor kernels&#039;&#039;&#039;&lt;br /&gt;
:All modern Linux distributions include support for XFS. &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;XFS userspace&#039;&#039;&#039;&lt;br /&gt;
:[https://kernel.org/pub/linux/utils/fs/xfs source code tarballs] of the xfs userspace tools. These tarballs form the basis of the xfsprogs packages found in Linux distributions.&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;font face=&amp;quot;ARIAL NARROW,HELVETICA&amp;quot;&amp;gt; Development and bleeding edge Development &amp;lt;/font&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
* [[XFS git howto]]&lt;br /&gt;
&lt;br /&gt;
=== Current XFS kernel source ===&lt;br /&gt;
&lt;br /&gt;
* [https://git.kernel.org/cgit/linux/kernel/git/dgc/linux-xfs.git/ xfs]&lt;br /&gt;
&lt;br /&gt;
 $ git clone git://git.kernel.org/pub/scm/linux/kernel/git/dgc/linux-xfs.git &lt;br /&gt;
&lt;br /&gt;
Note: the old kernel tree on [http://oss.sgi.com/cgi-bin/gitweb.cgi oss.sgi.com] is no longer kept up to date with the master tree on kernel.org.&lt;br /&gt;
&lt;br /&gt;
=== XFS user space tools ===&lt;br /&gt;
* [https://git.kernel.org/cgit/fs/xfs/xfsprogs-dev.git/ xfsprogs ]&lt;br /&gt;
&lt;br /&gt;
 git clone git://git.kernel.org/pub/scm/fs/xfs/xfsprogs-dev.git&lt;br /&gt;
&lt;br /&gt;
A few packages are needed to compile &amp;lt;tt&amp;gt;xfsprogs&amp;lt;/tt&amp;gt;, depending on your package manager:&lt;br /&gt;
&lt;br /&gt;
 apt-get install libtool automake gettext libblkid-dev uuid-dev&lt;br /&gt;
 yum     install libtool automake gettext libblkid-devel libuuid-devel&lt;br /&gt;
&lt;br /&gt;
=== XFS dump ===&lt;br /&gt;
* [https://git.kernel.org/cgit/fs/xfs/xfsdump-dev.git/ xfsdump ]&lt;br /&gt;
&lt;br /&gt;
 git clone git://git.kernel.org/pub/scm/fs/xfs/xfsdump-dev.git&lt;br /&gt;
&lt;br /&gt;
=== XFS tests ===&lt;br /&gt;
* [https://git.kernel.org/cgit/fs/xfs/xfstests-dev.git/ xfstests ]&lt;br /&gt;
&lt;br /&gt;
 git clone git://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git&lt;br /&gt;
&lt;br /&gt;
=== DMAPI user space tools ===&lt;br /&gt;
* [https://git.kernel.org/cgit/fs/xfs/dmapi-dev.git/ dmapi ]&lt;br /&gt;
&lt;br /&gt;
 git clone git://git.kernel.org/pub/scm/fs/xfs/dmapi-dev.git&lt;br /&gt;
&lt;br /&gt;
=== git-cvsimport generated trees ===&lt;br /&gt;
&lt;br /&gt;
The Git trees are automated mirrored copies of the CVS trees using [http://www.kernel.org/pub/software/scm/git/docs/git-cvsimport.html git-cvsimport].&lt;br /&gt;
Since git-cvsimport utilized the tool [http://www.cobite.com/cvsps/ cvsps] to recreate the atomic commits of ptools or &amp;quot;mod&amp;quot; it is easier to see the entire change that was committed using git.&lt;br /&gt;
&lt;br /&gt;
* [http://oss.sgi.com/cgi-bin/gitweb.cgi?p=archive/xfs-import.git;a=summary linux-2.6-xfs-from-cvs]&lt;br /&gt;
* [http://oss.sgi.com/cgi-bin/gitweb.cgi?p=archive/xfs-cmds.git;a=summary xfs-cmds]&lt;br /&gt;
&lt;br /&gt;
Before building in the &amp;lt;tt&amp;gt;xfsdump&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;dmapi&amp;lt;/tt&amp;gt; directories (after building &amp;lt;tt&amp;gt;xfsprogs&amp;lt;/tt&amp;gt;), you will need to run:&lt;br /&gt;
  # cd xfsprogs&lt;br /&gt;
  # make install-dev&lt;br /&gt;
to create &amp;lt;tt&amp;gt;/usr/include/xfs&amp;lt;/tt&amp;gt; and install appropriate files there.&lt;br /&gt;
&lt;br /&gt;
Before building in the xfstests directory, you will need to run:&lt;br /&gt;
  # cd xfsprogs&lt;br /&gt;
  # make install-qa&lt;br /&gt;
to install a somewhat larger set of files in &amp;lt;tt&amp;gt;/usr/include/xfs&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;font face=&amp;quot;ARIAL NARROW,HELVETICA&amp;quot;&amp;gt;XFS cvs trees &amp;lt;/font&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
The cvs trees were created using a script that converted sgi&#039;s internal&lt;br /&gt;
ptools repository to a cvs repository, so the cvs trees were considered read only.&lt;br /&gt;
&lt;br /&gt;
At this point all new development is being managed by the git trees thus the cvs trees&lt;br /&gt;
are no longer active in terms of current development and should only be used&lt;br /&gt;
for reference.&lt;br /&gt;
&lt;br /&gt;
* [[XFS CVS howto]]&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=Getting_the_latest_source_code&amp;diff=2995</id>
		<title>Getting the latest source code</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=Getting_the_latest_source_code&amp;diff=2995"/>
		<updated>2016-08-30T01:45:30Z</updated>

		<summary type="html">&lt;p&gt;Dgc: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== &amp;lt;font face=&amp;quot;ARIAL NARROW,HELVETICA&amp;quot;&amp;gt; XFS Released/Stable source &amp;lt;/font&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Note: as of September 2016, the XFS project is moving away from oss.sgi.com infrastructure. As we move to other infrastructure the links below will be updated to point to the new locations.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Mainline kernels&#039;&#039;&#039;&lt;br /&gt;
:XFS has been maintained in the official Linux kernel [http://www.kernel.org/ kernel trees] starting with [http://lkml.org/lkml/2003/12/8/35 Linux 2.4] and is frequently updated with the latest stable fixes and features from the XFS development team.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Vendor kernels&#039;&#039;&#039;&lt;br /&gt;
:All modern Linux distributions include support for XFS. &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;XFS userspace&#039;&#039;&#039;&lt;br /&gt;
:[ftp://oss.sgi.com/projects/xfs source code tarballs] of the xfs userspace tools. These tarballs form the basis of the xfsprogs packages found in Linux distributions.&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;font face=&amp;quot;ARIAL NARROW,HELVETICA&amp;quot;&amp;gt; Development and bleeding edge Development &amp;lt;/font&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
* [[XFS git howto]]&lt;br /&gt;
&lt;br /&gt;
=== Current XFS kernel source ===&lt;br /&gt;
&lt;br /&gt;
* [https://git.kernel.org/cgit/linux/kernel/git/dgc/linux-xfs.git/ xfs]&lt;br /&gt;
&lt;br /&gt;
 $ git clone git://git.kernel.org/pub/scm/linux/kernel/git/dgc/linux-xfs.git &lt;br /&gt;
&lt;br /&gt;
Note: the old kernel tree on [http://oss.sgi.com/cgi-bin/gitweb.cgi oss.sgi.com] is no longer kept up to date with the master tree on kernel.org.&lt;br /&gt;
&lt;br /&gt;
=== XFS user space tools ===&lt;br /&gt;
* [https://git.kernel.org/cgit/fs/xfs/xfsprogs-dev.git/ xfsprogs ]&lt;br /&gt;
&lt;br /&gt;
 git clone git://git.kernel.org/pub/scm/fs/xfs/xfsprogs-dev.git&lt;br /&gt;
&lt;br /&gt;
A few packages are needed to compile &amp;lt;tt&amp;gt;xfsprogs&amp;lt;/tt&amp;gt;, depending on your package manager:&lt;br /&gt;
&lt;br /&gt;
 apt-get install libtool automake gettext libblkid-dev uuid-dev&lt;br /&gt;
 yum     install libtool automake gettext libblkid-devel libuuid-devel&lt;br /&gt;
&lt;br /&gt;
=== XFS dump ===&lt;br /&gt;
* [https://git.kernel.org/cgit/fs/xfs/xfsdump-dev.git/ xfsdump ]&lt;br /&gt;
&lt;br /&gt;
 git clone git://git.kernel.org/pub/scm/fs/xfs/xfsdump-dev.git&lt;br /&gt;
&lt;br /&gt;
=== XFS tests ===&lt;br /&gt;
* [https://git.kernel.org/cgit/fs/xfs/xfstests-dev.git/ xfstests ]&lt;br /&gt;
&lt;br /&gt;
 git clone git://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git&lt;br /&gt;
&lt;br /&gt;
=== DMAPI user space tools ===&lt;br /&gt;
* [https://git.kernel.org/cgit/fs/xfs/dmapi-dev.git/ dmapi ]&lt;br /&gt;
&lt;br /&gt;
 git clone git://git.kernel.org/pub/scm/fs/xfs/dmapi-dev.git&lt;br /&gt;
&lt;br /&gt;
=== git-cvsimport generated trees ===&lt;br /&gt;
&lt;br /&gt;
The Git trees are automated mirrored copies of the CVS trees using [http://www.kernel.org/pub/software/scm/git/docs/git-cvsimport.html git-cvsimport].&lt;br /&gt;
Since git-cvsimport utilized the tool [http://www.cobite.com/cvsps/ cvsps] to recreate the atomic commits of ptools or &amp;quot;mod&amp;quot; it is easier to see the entire change that was committed using git.&lt;br /&gt;
&lt;br /&gt;
* [http://oss.sgi.com/cgi-bin/gitweb.cgi?p=archive/xfs-import.git;a=summary linux-2.6-xfs-from-cvs]&lt;br /&gt;
* [http://oss.sgi.com/cgi-bin/gitweb.cgi?p=archive/xfs-cmds.git;a=summary xfs-cmds]&lt;br /&gt;
&lt;br /&gt;
Before building in the &amp;lt;tt&amp;gt;xfsdump&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;dmapi&amp;lt;/tt&amp;gt; directories (after building &amp;lt;tt&amp;gt;xfsprogs&amp;lt;/tt&amp;gt;), you will need to run:&lt;br /&gt;
  # cd xfsprogs&lt;br /&gt;
  # make install-dev&lt;br /&gt;
to create &amp;lt;tt&amp;gt;/usr/include/xfs&amp;lt;/tt&amp;gt; and install appropriate files there.&lt;br /&gt;
&lt;br /&gt;
Before building in the xfstests directory, you will need to run:&lt;br /&gt;
  # cd xfsprogs&lt;br /&gt;
  # make install-qa&lt;br /&gt;
to install a somewhat larger set of files in &amp;lt;tt&amp;gt;/usr/include/xfs&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;font face=&amp;quot;ARIAL NARROW,HELVETICA&amp;quot;&amp;gt;XFS cvs trees &amp;lt;/font&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
The cvs trees were created using a script that converted sgi&#039;s internal&lt;br /&gt;
ptools repository to a cvs repository, so the cvs trees were considered read only.&lt;br /&gt;
&lt;br /&gt;
At this point all new development is being managed by the git trees thus the cvs trees&lt;br /&gt;
are no longer active in terms of current development and should only be used&lt;br /&gt;
for reference.&lt;br /&gt;
&lt;br /&gt;
* [[XFS CVS howto]]&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=XFS_email_list_and_archives&amp;diff=2994</id>
		<title>XFS email list and archives</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=XFS_email_list_and_archives&amp;diff=2994"/>
		<updated>2016-08-30T01:35:55Z</updated>

		<summary type="html">&lt;p&gt;Dgc: moving mailing list to vger.kernel.org&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== XFS email list ==&lt;br /&gt;
Patches, comments, requests and questions should go to [mailto:linux-xfs@vger.kernel.org linux-xfs@vger.kernel.org]&lt;br /&gt;
&lt;br /&gt;
As of September 2016, the XFS will move from the long standing address of xfs@oss.sgi.com because of the propsective shutdown of the oss.sgi.com infrastructure. See below for links to the old archives.&lt;br /&gt;
&lt;br /&gt;
Current crchives of the linux-xfs@vger.kernel.org list can be found at&lt;br /&gt;
&lt;br /&gt;
* [http://www.spinics.net/lists/linux-xfs/ Spinics]&lt;br /&gt;
&lt;br /&gt;
== Subscribing to the list ==&lt;br /&gt;
&lt;br /&gt;
Details for subscribing to the list can be found at the [http://vger.kernel.org/vger-lists.html#linux-xfs vger list info page].&lt;br /&gt;
&lt;br /&gt;
Subscribing is *only* possible by sending an email with the body:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;subscribe linux-xfs&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
to [mailto:majordomo@vger.kernel.org majordomo@vger.kernel.org]&lt;br /&gt;
&lt;br /&gt;
== Old XFS archives ==&lt;br /&gt;
&lt;br /&gt;
The list archives on oss.sgi.com are available [http://oss.sgi.com/archives/xfs here] (MHonArc) and [http://oss.sgi.com/pipermail/xfs here] (mailman).&lt;br /&gt;
&lt;br /&gt;
Other archives include:&lt;br /&gt;
&lt;br /&gt;
* [https://www.spinics.net/lists/xfs/ Spinics]&lt;br /&gt;
* [http://www.opensubscriber.com/messages/xfs@oss.sgi.com/topic.html OpenSubscriber]&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=Host_Aware_SMR_architecture&amp;diff=2974</id>
		<title>Host Aware SMR architecture</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=Host_Aware_SMR_architecture&amp;diff=2974"/>
		<updated>2015-03-16T05:49:12Z</updated>

		<summary type="html">&lt;p&gt;Dgc: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The first proposal for optimising XFS for host aware SMR drives can be found in the upstream XFS documentation repository [https://git.kernel.org/cgit/fs/xfs/xfs-documentation.git/tree/design/xfs-smr-structure.asciidoc here].&lt;br /&gt;
&lt;br /&gt;
A pdf version of this document (built from commit 1708324fdd1d37619db316d7023b7115837ae39d) can be found here: [[File:Xfs-smr-structure-0.2.pdf]].&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=File:Xfs-smr-structure-0.2.pdf&amp;diff=2973</id>
		<title>File:Xfs-smr-structure-0.2.pdf</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=File:Xfs-smr-structure-0.2.pdf&amp;diff=2973"/>
		<updated>2015-03-16T05:45:56Z</updated>

		<summary type="html">&lt;p&gt;Dgc: XFS SMR architecture proposal v0.2&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;XFS SMR architecture proposal v0.2&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=Host_Aware_SMR_architecture&amp;diff=2972</id>
		<title>Host Aware SMR architecture</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=Host_Aware_SMR_architecture&amp;diff=2972"/>
		<updated>2015-03-16T05:44:38Z</updated>

		<summary type="html">&lt;p&gt;Dgc: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The first proposal for optimising XFS for host aware canbe found in the upstream XFS documentation repository [https://git.kernel.org/cgit/fs/xfs/xfs-documentation.git/tree/design/xfs-smr-structure.asciidoc here].&lt;br /&gt;
&lt;br /&gt;
A pdf version of this document (built from commit 1708324fdd1d37619db316d7023b7115837ae39d) is attached here.&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=Host_Aware_SMR_architecture&amp;diff=2971</id>
		<title>Host Aware SMR architecture</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=Host_Aware_SMR_architecture&amp;diff=2971"/>
		<updated>2015-03-16T05:42:52Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Created page with &amp;quot;Host Aware SMR Architecture  The first proposal for optimising XFS for host aware canbe found in the upstream XFS documentation repository [https://git.kernel.org/cgit/fs/xfs/...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Host Aware SMR Architecture&lt;br /&gt;
&lt;br /&gt;
The first proposal for optimising XFS for host aware canbe found in the upstream XFS documentation repository [https://git.kernel.org/cgit/fs/xfs/xfs-documentation.git/tree/design/xfs-smr-structure.asciidoc here].&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=Ideas_for_XFS&amp;diff=2970</id>
		<title>Ideas for XFS</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=Ideas_for_XFS&amp;diff=2970"/>
		<updated>2015-03-16T05:37:55Z</updated>

		<summary type="html">&lt;p&gt;Dgc: add link for new document&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Future Directions for XFS =&lt;br /&gt;
&lt;br /&gt;
Dave Chinner&#039;s ideas from 2008:&lt;br /&gt;
&lt;br /&gt;
* [[Improving inode Caching]]&lt;br /&gt;
&lt;br /&gt;
* [[Improving Metadata Performance By Reducing Journal Overhead]]&lt;br /&gt;
&lt;br /&gt;
* [[Reliable Detection and Repair of Metadata Corruption]]&lt;br /&gt;
&lt;br /&gt;
Other ideas:&lt;br /&gt;
&lt;br /&gt;
* [[Splitting project quota support from group quota support]]&lt;br /&gt;
&lt;br /&gt;
* [[Assigning project quota to a linux container]]&lt;br /&gt;
&lt;br /&gt;
* [[Support discarding of unused sectors]] (status: completed)&lt;br /&gt;
&lt;br /&gt;
* Superblock flag for when 64-bit inodes are present (see [http://oss.sgi.com/pipermail/xfs/2009-May/041379.html xfs: regarding the inode64 mount option])&lt;br /&gt;
&lt;br /&gt;
* Wishlist: Please integrate &#039;&#039;xfs_irecover&#039;&#039; or provide [http://www.who.is.free.fr/wiki/doku.php?id=recover inode recovery feature]&lt;br /&gt;
&lt;br /&gt;
* [[Host Aware SMR architecture]]&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=Getting_the_latest_source_code&amp;diff=2955</id>
		<title>Getting the latest source code</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=Getting_the_latest_source_code&amp;diff=2955"/>
		<updated>2015-01-22T04:13:41Z</updated>

		<summary type="html">&lt;p&gt;Dgc: update for new master kernel source tree repo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== &amp;lt;font face=&amp;quot;ARIAL NARROW,HELVETICA&amp;quot;&amp;gt; XFS Released/Stable source &amp;lt;/font&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Mainline kernels&#039;&#039;&#039;&lt;br /&gt;
:XFS has been maintained in the official Linux kernel [http://www.kernel.org/ kernel trees] starting with [http://lkml.org/lkml/2003/12/8/35 Linux 2.4] and is frequently updated with the latest stable fixes and features from the XFS development team.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Vendor kernels&#039;&#039;&#039;&lt;br /&gt;
:All modern Linux distributions include support for XFS. &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;XFS userspace&#039;&#039;&#039;&lt;br /&gt;
:[ftp://oss.sgi.com/projects/xfs source code tarballs] of the xfs userspace tools. These tarballs form the basis of the xfsprogs packages found in Linux distributions.&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;font face=&amp;quot;ARIAL NARROW,HELVETICA&amp;quot;&amp;gt; Development and bleeding edge Development &amp;lt;/font&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
* [[XFS git howto]]&lt;br /&gt;
&lt;br /&gt;
=== Current XFS kernel source ===&lt;br /&gt;
* [https://git.kernel.org/cgit/linux/kernel/git/dgc/linux-xfs.git/ xfs]&lt;br /&gt;
 $ git clone git://git.kernel.org/pub/scm/linux/kernel/git/dgc/linux-xfs.git &lt;br /&gt;
&lt;br /&gt;
Note: the old kernel tree on [http://oss.sgi.com/cgi-bin/gitweb.cgi oss.sgi.com] i sno longer kept up to date with the master tree on kernel.org.&lt;br /&gt;
&lt;br /&gt;
=== XFS user space tools ===&lt;br /&gt;
* [http://oss.sgi.com/cgi-bin/gitweb.cgi?p=xfs/cmds/xfsprogs.git;a=summary xfsprogs]&lt;br /&gt;
&lt;br /&gt;
 git clone git://oss.sgi.com/xfs/cmds/xfsprogs&lt;br /&gt;
&lt;br /&gt;
A few packages are needed to compile &amp;lt;tt&amp;gt;xfsprogs&amp;lt;/tt&amp;gt;, depending on your package manager:&lt;br /&gt;
&lt;br /&gt;
 apt-get install libtool automake gettext libblkid-dev uuid-dev&lt;br /&gt;
 yum     install libtool automake gettext libblkid-devel libuuid-devel&lt;br /&gt;
&lt;br /&gt;
=== XFS dump ===&lt;br /&gt;
* [http://oss.sgi.com/cgi-bin/gitweb.cgi?p=xfs/cmds/xfsdump.git;a=summary xfsdump]&lt;br /&gt;
 $ git clone git://oss.sgi.com/xfs/cmds/xfsdump&lt;br /&gt;
&lt;br /&gt;
=== XFS tests ===&lt;br /&gt;
* [http://oss.sgi.com/cgi-bin/gitweb.cgi?p=xfs/cmds/xfstests.git;a=summary xfstests]&lt;br /&gt;
 $ git clone git://oss.sgi.com/xfs/cmds/xfstests&lt;br /&gt;
&lt;br /&gt;
=== DMAPI user space tools ===&lt;br /&gt;
* [http://oss.sgi.com/cgi-bin/gitweb.cgi?p=xfs/cmds/dmapi.git;a=summary dmapi]&lt;br /&gt;
 $ git clone git://oss.sgi.com/xfs/cmds/dmapi&lt;br /&gt;
&lt;br /&gt;
=== git-cvsimport generated trees ===&lt;br /&gt;
&lt;br /&gt;
The Git trees are automated mirrored copies of the CVS trees using [http://www.kernel.org/pub/software/scm/git/docs/git-cvsimport.html git-cvsimport].&lt;br /&gt;
Since git-cvsimport utilized the tool [http://www.cobite.com/cvsps/ cvsps] to recreate the atomic commits of ptools or &amp;quot;mod&amp;quot; it is easier to see the entire change that was committed using git.&lt;br /&gt;
&lt;br /&gt;
* [http://oss.sgi.com/cgi-bin/gitweb.cgi?p=archive/xfs-import.git;a=summary linux-2.6-xfs-from-cvs]&lt;br /&gt;
* [http://oss.sgi.com/cgi-bin/gitweb.cgi?p=archive/xfs-cmds.git;a=summary xfs-cmds]&lt;br /&gt;
&lt;br /&gt;
Before building in the &amp;lt;tt&amp;gt;xfsdump&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;dmapi&amp;lt;/tt&amp;gt; directories (after building &amp;lt;tt&amp;gt;xfsprogs&amp;lt;/tt&amp;gt;), you will need to run:&lt;br /&gt;
  # cd xfsprogs&lt;br /&gt;
  # make install-dev&lt;br /&gt;
to create &amp;lt;tt&amp;gt;/usr/include/xfs&amp;lt;/tt&amp;gt; and install appropriate files there.&lt;br /&gt;
&lt;br /&gt;
Before building in the xfstests directory, you will need to run:&lt;br /&gt;
  # cd xfsprogs&lt;br /&gt;
  # make install-qa&lt;br /&gt;
to install a somewhat larger set of files in &amp;lt;tt&amp;gt;/usr/include/xfs&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;font face=&amp;quot;ARIAL NARROW,HELVETICA&amp;quot;&amp;gt;XFS cvs trees &amp;lt;/font&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
The cvs trees were created using a script that converted sgi&#039;s internal&lt;br /&gt;
ptools repository to a cvs repository, so the cvs trees were considered read only.&lt;br /&gt;
&lt;br /&gt;
At this point all new development is being managed by the git trees thus the cvs trees&lt;br /&gt;
are no longer active in terms of current development and should only be used&lt;br /&gt;
for reference.&lt;br /&gt;
&lt;br /&gt;
* [[XFS CVS howto]]&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=User_talk:Ronan_David&amp;diff=2947</id>
		<title>User talk:Ronan David</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=User_talk:Ronan_David&amp;diff=2947"/>
		<updated>2014-07-08T23:47:13Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Welcome!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Welcome to &#039;&#039;XFS.org&#039;&#039;!&#039;&#039;&#039;&lt;br /&gt;
We hope you will contribute much and well.&lt;br /&gt;
You will probably want to read the [[Help:Contents|help pages]].&lt;br /&gt;
Again, welcome and have fun! [[User:Dgc|Dgc]] ([[User talk:Dgc|talk]]) 23:47, 8 July 2014 (UTC)&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=User:Ronan_David&amp;diff=2946</id>
		<title>User:Ronan David</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=User:Ronan_David&amp;diff=2946"/>
		<updated>2014-07-08T23:47:13Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Creating user page for new user.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I&#039;m a project manager on a product installed on linux&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=User_talk:Fengyongzhen&amp;diff=2942</id>
		<title>User talk:Fengyongzhen</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=User_talk:Fengyongzhen&amp;diff=2942"/>
		<updated>2014-04-16T20:36:43Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Welcome!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Welcome to &#039;&#039;XFS.org&#039;&#039;!&#039;&#039;&#039;&lt;br /&gt;
We hope you will contribute much and well.&lt;br /&gt;
You will probably want to read the [[Help:Contents|help pages]].&lt;br /&gt;
Again, welcome and have fun! [[User:Dgc|Dgc]] ([[User talk:Dgc|talk]]) 20:36, 16 April 2014 (UTC)&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=User:Fengyongzhen&amp;diff=2941</id>
		<title>User:Fengyongzhen</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=User:Fengyongzhen&amp;diff=2941"/>
		<updated>2014-04-16T20:36:43Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Creating user page for new user.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;try to learn how to use xfs，at least support 16T disk。&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=User_talk:William_M._Moss&amp;diff=2940</id>
		<title>User talk:William M. Moss</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=User_talk:William_M._Moss&amp;diff=2940"/>
		<updated>2014-04-16T20:35:54Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Welcome!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Welcome to &#039;&#039;XFS.org&#039;&#039;!&#039;&#039;&#039;&lt;br /&gt;
We hope you will contribute much and well.&lt;br /&gt;
You will probably want to read the [[Help:Contents|help pages]].&lt;br /&gt;
Again, welcome and have fun! [[User:Dgc|Dgc]] ([[User talk:Dgc|talk]]) 20:35, 16 April 2014 (UTC)&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=User:William_M._Moss&amp;diff=2939</id>
		<title>User:William M. Moss</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=User:William_M._Moss&amp;diff=2939"/>
		<updated>2014-04-16T20:35:54Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Creating user page for new user.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Retired&lt;br /&gt;
Using Unix since Lab Version 7.&lt;br /&gt;
Using Linux since version 1.13.&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=User_talk:Brian_Foster&amp;diff=2938</id>
		<title>User talk:Brian Foster</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=User_talk:Brian_Foster&amp;diff=2938"/>
		<updated>2014-04-16T20:35:38Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Welcome!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Welcome to &#039;&#039;XFS.org&#039;&#039;!&#039;&#039;&#039;&lt;br /&gt;
We hope you will contribute much and well.&lt;br /&gt;
You will probably want to read the [[Help:Contents|help pages]].&lt;br /&gt;
Again, welcome and have fun! [[User:Dgc|Dgc]] ([[User talk:Dgc|talk]]) 20:35, 16 April 2014 (UTC)&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=User:Brian_Foster&amp;diff=2937</id>
		<title>User:Brian Foster</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=User:Brian_Foster&amp;diff=2937"/>
		<updated>2014-04-16T20:35:36Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Creating user page for new user.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Brian is an XFS hacker at Red Hat. He wrote this second sentence to satisfy the biography length requirement.&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=User_talk:Avishay&amp;diff=2844</id>
		<title>User talk:Avishay</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=User_talk:Avishay&amp;diff=2844"/>
		<updated>2013-06-15T01:14:34Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Welcome!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Welcome to &#039;&#039;XFS.org&#039;&#039;!&#039;&#039;&#039;&lt;br /&gt;
We hope you will contribute much and well.&lt;br /&gt;
You will probably want to read the [[Help:Contents|help pages]].&lt;br /&gt;
Again, welcome and have fun! [[User:Dgc|Dgc]] ([[User talk:Dgc|talk]]) 01:14, 15 June 2013 (UTC)&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=User:Avishay&amp;diff=2843</id>
		<title>User:Avishay</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=User:Avishay&amp;diff=2843"/>
		<updated>2013-06-15T01:14:34Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Creating user page for new user.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Development Manager of Credit Cards and ATM.&lt;br /&gt;
Management of large scale software projects within a variety of environments, managing 18 SW engineers(3 Teams).&lt;br /&gt;
experience in technical analysis and evaluation, budget estimates, Project Management, recruitment and training, tool selection and implementation, configuration management, quality assurance and testing.&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=User_talk:Benjamin_Myers&amp;diff=2839</id>
		<title>User talk:Benjamin Myers</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=User_talk:Benjamin_Myers&amp;diff=2839"/>
		<updated>2013-05-03T02:07:32Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Welcome!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Welcome to &#039;&#039;XFS.org&#039;&#039;!&#039;&#039;&#039;&lt;br /&gt;
We hope you will contribute much and well.&lt;br /&gt;
You will probably want to read the [[Help:Contents|help pages]].&lt;br /&gt;
Again, welcome and have fun! [[User:Dgc|Dgc]] ([[User talk:Dgc|talk]]) 02:07, 3 May 2013 (UTC)&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=User:Benjamin_Myers&amp;diff=2838</id>
		<title>User:Benjamin Myers</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=User:Benjamin_Myers&amp;diff=2838"/>
		<updated>2013-05-03T02:07:32Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Creating user page for new user.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;one two three four five six seven eight nine ten&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=User_talk:Ben_Myers&amp;diff=2837</id>
		<title>User talk:Ben Myers</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=User_talk:Ben_Myers&amp;diff=2837"/>
		<updated>2013-05-03T02:03:54Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Welcome!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Welcome to &#039;&#039;XFS.org&#039;&#039;!&#039;&#039;&#039;&lt;br /&gt;
We hope you will contribute much and well.&lt;br /&gt;
You will probably want to read the [[Help:Contents|help pages]].&lt;br /&gt;
Again, welcome and have fun! [[User:Dgc|Dgc]] ([[User talk:Dgc|talk]]) 02:03, 3 May 2013 (UTC)&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=User:Ben_Myers&amp;diff=2836</id>
		<title>User:Ben Myers</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=User:Ben_Myers&amp;diff=2836"/>
		<updated>2013-05-03T02:03:54Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Creating user page for new user.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This biography must be at least 10 words long.  Ten.  Eleven.&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=User_talk:Geoffrey_Wehrman&amp;diff=2835</id>
		<title>User talk:Geoffrey Wehrman</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=User_talk:Geoffrey_Wehrman&amp;diff=2835"/>
		<updated>2013-05-03T02:03:16Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Welcome!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Welcome to &#039;&#039;XFS.org&#039;&#039;!&#039;&#039;&#039;&lt;br /&gt;
We hope you will contribute much and well.&lt;br /&gt;
You will probably want to read the [[Help:Contents|help pages]].&lt;br /&gt;
Again, welcome and have fun! [[User:Dgc|Dgc]] ([[User talk:Dgc|talk]]) 02:03, 3 May 2013 (UTC)&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=User:Geoffrey_Wehrman&amp;diff=2834</id>
		<title>User:Geoffrey Wehrman</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=User:Geoffrey_Wehrman&amp;diff=2834"/>
		<updated>2013-05-03T02:03:16Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Creating user page for new user.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Filesystem developer at SGI since 1997.&lt;br /&gt;
Experience with XFS on IRIX and Linux.&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=User_talk:Chandra_Seetharaman&amp;diff=2833</id>
		<title>User talk:Chandra Seetharaman</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=User_talk:Chandra_Seetharaman&amp;diff=2833"/>
		<updated>2013-05-03T02:02:50Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Welcome!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Welcome to &#039;&#039;XFS.org&#039;&#039;!&#039;&#039;&#039;&lt;br /&gt;
We hope you will contribute much and well.&lt;br /&gt;
You will probably want to read the [[Help:Contents|help pages]].&lt;br /&gt;
Again, welcome and have fun! [[User:Dgc|Dgc]] ([[User talk:Dgc|talk]]) 02:02, 3 May 2013 (UTC)&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=User:Chandra_Seetharaman&amp;diff=2832</id>
		<title>User:Chandra Seetharaman</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=User:Chandra_Seetharaman&amp;diff=2832"/>
		<updated>2013-05-03T02:02:50Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Creating user page for new user.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Has been working on different part of linux kernel for more than a decade, which include filesystem too.&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=User_talk:Mariusz_Witek&amp;diff=2819</id>
		<title>User talk:Mariusz Witek</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=User_talk:Mariusz_Witek&amp;diff=2819"/>
		<updated>2012-10-12T07:00:50Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Welcome!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Welcome to &#039;&#039;XFS.org&#039;&#039;!&#039;&#039;&#039;&lt;br /&gt;
We hope you will contribute much and well.&lt;br /&gt;
You will probably want to read the [[Help:Contents|help pages]].&lt;br /&gt;
Again, welcome and have fun! [[User:Dgc|Dgc]] ([[User talk:Dgc|talk]]) 07:00, 12 October 2012 (UTC)&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=User:Mariusz_Witek&amp;diff=2818</id>
		<title>User:Mariusz Witek</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=User:Mariusz_Witek&amp;diff=2818"/>
		<updated>2012-10-12T07:00:50Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Creating user page for new user.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I am physicist working in the research institute with some computing background.&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=XFS_FAQ&amp;diff=2815</id>
		<title>XFS FAQ</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=XFS_FAQ&amp;diff=2815"/>
		<updated>2012-08-13T23:58:57Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Reverted edits by Zmi (talk) to last revision by Sandeen&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Info from: [http://oss.sgi.com/projects/xfs/faq.html main XFS faq at SGI]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Many thanks to earlier maintainers of this document - Thomas Graichen and Seth Mos.&lt;br /&gt;
&lt;br /&gt;
== Q: Where can I find documentation about XFS? ==&lt;br /&gt;
&lt;br /&gt;
The SGI XFS project page http://oss.sgi.com/projects/xfs/ is the definitive reference. It contains pointers to whitepapers, books, articles, etc.&lt;br /&gt;
&lt;br /&gt;
You could also join the [[XFS_email_list_and_archives|XFS mailing list]] or the &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;#xfs&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039; IRC channel on &#039;&#039;irc.freenode.net&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Q: Where can I find documentation about ACLs? ==&lt;br /&gt;
&lt;br /&gt;
Andreas Gruenbacher maintains the Extended Attribute and POSIX ACL documentation for Linux at http://acl.bestbits.at/&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;acl(5)&#039;&#039;&#039; manual page is also quite extensive.&lt;br /&gt;
&lt;br /&gt;
== Q: Where can I find information about the internals of XFS? ==&lt;br /&gt;
&lt;br /&gt;
An [http://oss.sgi.com/projects/xfs/training/ SGI XFS Training course] aimed at developers, triage and support staff, and serious users has been in development. Parts of the course are clearly still incomplete, but there is enough content to be useful to a broad range of users.&lt;br /&gt;
&lt;br /&gt;
Barry Naujok has documented the [http://oss.sgi.com/projects/xfs/papers/xfs_filesystem_structure.pdf XFS ondisk format] which is a very useful reference.&lt;br /&gt;
&lt;br /&gt;
== Q: What partition type should I use for XFS on Linux? ==&lt;br /&gt;
&lt;br /&gt;
Linux native filesystem (83).&lt;br /&gt;
&lt;br /&gt;
== Q: What mount options does XFS have? ==&lt;br /&gt;
&lt;br /&gt;
There are a number of mount options influencing XFS filesystems - refer to the &#039;&#039;&#039;mount(8)&#039;&#039;&#039; manual page or the documentation in the kernel source tree itself ([http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/filesystems/xfs.txt;hb=HEAD Documentation/filesystems/xfs.txt])&lt;br /&gt;
&lt;br /&gt;
== Q: Is there any relation between the XFS utilities and the kernel version? ==&lt;br /&gt;
&lt;br /&gt;
No, there is no relation. Newer utilities tend to mainly have fixes and checks the previous versions might not have. New features are also added in a backward compatible way - if they are enabled via mkfs, an incapable (old) kernel will recognize that it does not understand the new feature, and refuse to mount the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Q: Does it run on platforms other than i386? ==&lt;br /&gt;
&lt;br /&gt;
XFS runs on all of the platforms that Linux supports. It is more tested on the more common platforms, especially the i386 family. Its also well tested on the IA64 platform since thats the platform SGI Linux products use.&lt;br /&gt;
&lt;br /&gt;
== Q: Quota: Do quotas work on XFS? ==&lt;br /&gt;
&lt;br /&gt;
Yes.&lt;br /&gt;
&lt;br /&gt;
To use quotas with XFS, you need to enable XFS quota support when you configure your kernel. You also need to specify quota support when mounting. You can get the Linux quota utilities at their sourceforge website [http://sourceforge.net/projects/linuxquota/  http://sourceforge.net/projects/linuxquota/] or use &#039;&#039;&#039;xfs_quota(8)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Q: Quota: What&#039;s project quota? ==&lt;br /&gt;
&lt;br /&gt;
The  project  quota  is a quota mechanism in XFS can be used to implement a form of directory tree quota, where a specified directory and all of the files and subdirectories below it (i.e. a tree) can be restricted to using a subset of the available space in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Q: Quota: Can group quota and project quota be used at the same time? ==&lt;br /&gt;
&lt;br /&gt;
No, project quota cannot be used with group quota at the same time. On the other hand user quota and project quota can be used simultaneously.&lt;br /&gt;
&lt;br /&gt;
== Q: Quota: Is umounting prjquota (project quota) enabled fs and mounting it again with grpquota (group quota) removing prjquota limits previously set from fs (and vice versa) ? ==&lt;br /&gt;
&lt;br /&gt;
To be answered.&lt;br /&gt;
&lt;br /&gt;
== Q: Are there any dump/restore tools for XFS? ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;xfsdump(8)&#039;&#039;&#039; and &#039;&#039;&#039;xfsrestore(8)&#039;&#039;&#039; are fully supported. The tape format is the same as on IRIX, so tapes are interchangeable between operating systems.&lt;br /&gt;
&lt;br /&gt;
== Q: Does LILO work with XFS? ==&lt;br /&gt;
&lt;br /&gt;
This depends on where you install LILO.&lt;br /&gt;
&lt;br /&gt;
Yes, for MBR (Master Boot Record) installations.&lt;br /&gt;
&lt;br /&gt;
No, for root partition installations because the XFS superblock is written at block zero, where LILO would be installed. This is to maintain compatibility with the IRIX on-disk format, and will not be changed.&lt;br /&gt;
&lt;br /&gt;
== Q: Does GRUB work with XFS? ==&lt;br /&gt;
&lt;br /&gt;
There is native XFS filesystem support for GRUB starting with version 0.91 and onward. Unfortunately, GRUB used to make incorrect assumptions about being able to read a block device image while a filesystem is mounted and actively being written to, which could cause intermittent problems when using XFS. This has reportedly since been fixed, and the 0.97 version (at least) of GRUB is apparently stable.&lt;br /&gt;
&lt;br /&gt;
== Q: Can XFS be used for a root filesystem? ==&lt;br /&gt;
&lt;br /&gt;
Yes, with one caveat: Linux does not support an external XFS journal for the root filesystem via the &amp;quot;rootflags=&amp;quot; kernel parameter. To use an external journal for the root filesystem in Linux, an init ramdisk must mount the root filesystem with explicit &amp;quot;logdev=&amp;quot; specified. [http://mindplusplus.wordpress.com/2008/07/27/scratching-an-i.html More information here.]&lt;br /&gt;
&lt;br /&gt;
== Q: Will I be able to use my IRIX XFS filesystems on Linux? ==&lt;br /&gt;
&lt;br /&gt;
Yes. The on-disk format of XFS is the same on IRIX and Linux. Obviously, you should back-up your data before trying to move it between systems. Filesystems must be &amp;quot;clean&amp;quot; when moved (i.e. unmounted). If you plan to use IRIX filesystems on Linux keep the following points in mind: the kernel needs to have SGI partition support enabled; there is no XLV support in Linux, so you are unable to read IRIX filesystems which use the XLV volume manager; also not all blocksizes available on IRIX are available on Linux (only blocksizes less than or equal to the pagesize of the architecture: 4k for i386, ppc, ... 8k for alpha, sparc, ... is possible for now). Make sure that the directory format is version 2 on the IRIX filesystems (this is the default since IRIX 6.5.5). Linux can only read v2 directories.&lt;br /&gt;
&lt;br /&gt;
== Q: Is there a way to make a XFS filesystem larger or smaller? ==&lt;br /&gt;
&lt;br /&gt;
You can &#039;&#039;NOT&#039;&#039; make a XFS partition smaller online. The only way to shrink is to do a complete dump, mkfs and restore.&lt;br /&gt;
&lt;br /&gt;
An XFS filesystem may be enlarged by using &#039;&#039;&#039;xfs_growfs(8)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
If using partitions, you need to have free space after this partition to do so. Remove partition, recreate it larger with the &#039;&#039;exact same&#039;&#039; starting point. Run &#039;&#039;&#039;xfs_growfs&#039;&#039;&#039; to make the partition larger. Note - editing partition tables is a dangerous pastime, so back up your filesystem before doing so.&lt;br /&gt;
&lt;br /&gt;
Using XFS filesystems on top of a volume manager makes this a lot easier.&lt;br /&gt;
&lt;br /&gt;
== Q: What information should I include when reporting a problem? ==&lt;br /&gt;
&lt;br /&gt;
What you need to report depend on the problem you are seeing. Firstly, your machine hardware and storage configuration needs to be described. That includes:&lt;br /&gt;
&lt;br /&gt;
* kernel version (uname -a)&lt;br /&gt;
* xfsprogs version (xfs_repair -V)&lt;br /&gt;
* number of CPUs&lt;br /&gt;
* contents of /proc/meminfo&lt;br /&gt;
* contents of /proc/mounts&lt;br /&gt;
* contents of /proc/partitions&lt;br /&gt;
* RAID layout (hardware and/or software)&lt;br /&gt;
* LVM configuration&lt;br /&gt;
* type of disks you are using&lt;br /&gt;
* write cache status of drives&lt;br /&gt;
* size of BBWC and mode it is running in&lt;br /&gt;
* xfs_info output on the filesystem in question&lt;br /&gt;
* dmesg output showing all error messages and stack traces&lt;br /&gt;
 &lt;br /&gt;
Then you need to describe your workload that is causing the problem, and a demonstration of the bad behaviour that is occurring. If it is a performance problem, then 30s - 1 minute samples of:&lt;br /&gt;
&lt;br /&gt;
# iostat -x -d -m 5&lt;br /&gt;
# vmstat 5&lt;br /&gt;
 &lt;br /&gt;
can give us insight into the IO and memory utilisation of your machine at the time of the problem.&lt;br /&gt;
&lt;br /&gt;
If the filesystem is hanging, then capture the output of the dmesg command after running:&lt;br /&gt;
&lt;br /&gt;
 # echo w &amp;gt; /proc/sysrq-trigger&lt;br /&gt;
 # dmesg&lt;br /&gt;
&lt;br /&gt;
will tell us all the hung processes in the machine, often pointing us directly to the cause of the hang.&lt;br /&gt;
&lt;br /&gt;
And for advanced users, capturing an event trace using &#039;&#039;&#039;trace-cmd&#039;&#039;&#039; (git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/trace-cmd.git) will be very helpful. In many cases the XFS developers will ask for this information anyway, so it&#039;s a good idea to be ready with it in advance. Start the trace with this command, either from a directory not on an XFS filesystem or with an output file destination on a non-XFS filesystem:&lt;br /&gt;
&lt;br /&gt;
 # trace-cmd record -e xfs\*&lt;br /&gt;
&lt;br /&gt;
before the problem occurs, and once it has occurred, kill the trace-cmd with ctrl-C, and then run:&lt;br /&gt;
&lt;br /&gt;
 # trace-cmd report &amp;gt; trace_report.txt&lt;br /&gt;
&lt;br /&gt;
Compress the trace_report.txt file and include that with the bug report. The reason for trying to host the output of the record command on a different filesystem is so that the writing of the output file does not pollute the trace of the problem we are trying to diagnose.&lt;br /&gt;
&lt;br /&gt;
If you have a problem with &#039;&#039;&#039;xfs_repair(8)&#039;&#039;&#039;, make sure that you save the entire output of the problematic run so that the developers can see exactly where it encountered the problem. You might be asked to capture the metadata in the filesystem using &#039;&#039;&#039;xfs_metadump(8)&#039;&#039;&#039; (which obfuscates filenames and attributes to protect your privacy) and make the dump available for someone to analyse.&lt;br /&gt;
&lt;br /&gt;
== Q: Mounting an XFS filesystem does not work - what is wrong? ==&lt;br /&gt;
&lt;br /&gt;
If mount prints an error message something like:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
     mount: /dev/hda5 has wrong major or minor number&lt;br /&gt;
&lt;br /&gt;
you either do not have XFS compiled into the kernel (or you forgot to load the modules) or you did not use the &amp;quot;-t xfs&amp;quot; option on mount or the &amp;quot;xfs&amp;quot; option in &amp;lt;tt&amp;gt;/etc/fstab&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you get something like:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 mount: wrong fs type, bad option, bad superblock on /dev/sda1,&lt;br /&gt;
        or too many mounted file systems&lt;br /&gt;
&lt;br /&gt;
Refer to your system log file (&amp;lt;tt&amp;gt;/var/log/messages&amp;lt;/tt&amp;gt;) for a detailed diagnostic message from the kernel.&lt;br /&gt;
&lt;br /&gt;
== Q: Does the filesystem have an undelete capability? ==&lt;br /&gt;
&lt;br /&gt;
There is no undelete in XFS (so far).&lt;br /&gt;
&lt;br /&gt;
However at least some XFS driver implementations do not wipe file information nodes completely so there are chance to recover files with specialized commercial closed source software like [http://www.ufsexplorer.com/rdr_xfs.php Raise Data Recovery for XFS].&lt;br /&gt;
&lt;br /&gt;
In this kind of XFS driver implementation it does not re-use directory entries immediately so there are chance to get back recently deleted files even with their real names.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;xfs_irecover&#039;&#039; or &#039;&#039;xfsr&#039;&#039; may help too, [http://www.who.is.free.fr/wiki/doku.php?id=recover this site] has a few links.&lt;br /&gt;
&lt;br /&gt;
This applies to most recent Linux distributions (versions?), as well as to most popular NAS boxes that use embedded linux and XFS file system.&lt;br /&gt;
&lt;br /&gt;
Anyway, the best is to always keep backups.&lt;br /&gt;
&lt;br /&gt;
== Q: How can I backup a XFS filesystem and ACLs? ==&lt;br /&gt;
&lt;br /&gt;
You can backup a XFS filesystem with utilities like &#039;&#039;&#039;xfsdump(8)&#039;&#039;&#039; and standard &#039;&#039;&#039;tar(1)&#039;&#039;&#039; for standard files. If you want to backup ACLs you will need to use &#039;&#039;&#039;xfsdump&#039;&#039;&#039; or [http://www.bacula.org/en/dev-manual/Current_State_Bacula.html Bacula] (&amp;gt; version 3.1.4) or [http://rsync.samba.org/ rsync] (&amp;gt;= version 3.0.0) to backup ACLs and EAs. &#039;&#039;&#039;xfsdump&#039;&#039;&#039; can also be integrated with [http://www.amanda.org/ amanda(8)].&lt;br /&gt;
&lt;br /&gt;
== Q: I see applications returning error 990 or &amp;quot;Structure needs cleaning&amp;quot;, what is wrong? ==&lt;br /&gt;
&lt;br /&gt;
The error 990 stands for [http://oss.sgi.com/cgi-bin/gitweb.cgi?p=xfs/xfs.git;a=blob;f=fs/xfs/linux-2.6/xfs_linux.h#l145 EFSCORRUPTED] which usually means XFS has detected a filesystem metadata problem and has shut the filesystem down to prevent further damage. Also, since about June 2006, we [http://oss.sgi.com/cgi-bin/gitweb.cgi?p=xfs/xfs.git;a=commit;h=da2f4d679c8070ba5b6a920281e495917b293aa0 converted from EFSCORRUPTED/990 over to using EUCLEAN], &amp;quot;Structure needs cleaning.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The cause can be pretty much anything, unfortunately - filesystem, virtual memory manager, volume manager, device driver, or hardware.&lt;br /&gt;
&lt;br /&gt;
There should be a detailed console message when this initially happens. The messages have important information giving hints to developers as to the earliest point that a problem was detected. It is there to protect your data.&lt;br /&gt;
&lt;br /&gt;
You can use xfs_repair to remedy the problem (with the file system unmounted).&lt;br /&gt;
&lt;br /&gt;
== Q: Why do I see binary NULLS in some files after recovery when I unplugged the power? ==&lt;br /&gt;
&lt;br /&gt;
Update: This issue has been addressed with a CVS fix on the 29th March 2007 and merged into mainline on 8th May 2007 for 2.6.22-rc1.&lt;br /&gt;
&lt;br /&gt;
XFS journals metadata updates, not data updates. After a crash you are supposed to get a consistent filesystem which looks like the state sometime shortly before the crash, NOT what the in memory image looked like the instant before the crash.&lt;br /&gt;
&lt;br /&gt;
Since XFS does not write data out immediately unless you tell it to with fsync, an O_SYNC or O_DIRECT open (the same is true of other filesystems), you are looking at an inode which was flushed out, but whose data was not. Typically you&#039;ll find that the inode is not taking any space since all it has is a size but no extents allocated (try examining the file with the &#039;&#039;&#039;xfs_bmap(8)&#039;&#039;&#039; command).&lt;br /&gt;
&lt;br /&gt;
== Q: What is the problem with the write cache on journaled filesystems? ==&lt;br /&gt;
&lt;br /&gt;
Many drives use a write back cache in order to speed up the performance of writes.  However, there are conditions such as power failure when the write cache memory is never flushed to the actual disk.  Further, the drive can de-stage data from the write cache to the platters in any order that it chooses.  This causes problems for XFS and journaled filesystems in general because they rely on knowing when a write has completed to the disk. They need to know that the log information has made it to disk before allowing metadata to go to disk.  When the metadata makes it to disk then the transaction can effectively be deleted from the log resulting in movement of the tail of the log and thus freeing up some log space. So if the writes never make it to the physical disk, then the ordering is violated and the log and metadata can be lost, resulting in filesystem corruption.&lt;br /&gt;
&lt;br /&gt;
With hard disk cache sizes of currently (Jan 2009) up to 32MB that can be a lot of valuable information.  In a RAID with 8 such disks these adds to 256MB, and the chance of having filesystem metadata in the cache is so high that you have a very high chance of big data losses on a power outage.&lt;br /&gt;
&lt;br /&gt;
With a single hard disk and barriers turned on (on=default), the drive write cache is flushed before and after a barrier is issued.  A powerfail &amp;quot;only&amp;quot; loses data in the cache but no essential ordering is violated, and corruption will not occur.&lt;br /&gt;
&lt;br /&gt;
With a RAID controller with battery backed controller cache and cache in write back mode, you should turn off barriers - they are unnecessary in this case, and if the controller honors the cache flushes, it will be harmful to performance.  But then you *must* disable the individual hard disk write cache in order to ensure to keep the filesystem intact after a power failure. The method for doing this is different for each RAID controller. See the section about RAID controllers below.&lt;br /&gt;
&lt;br /&gt;
== Q: How can I tell if I have the disk write cache enabled? ==&lt;br /&gt;
&lt;br /&gt;
For SCSI/SATA:&lt;br /&gt;
&lt;br /&gt;
* Look in dmesg(8) output for a driver line, such as:&amp;lt;br /&amp;gt; &amp;quot;SCSI device sda: drive cache: write back&amp;quot;&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;# sginfo -c /dev/sda | grep -i &#039;write cache&#039; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For PATA/SATA (for SATA this requires at least kernel 2.6.15 because [http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=b095518ef51c37658c58367bd19240b8a113f25c ATA command passthrough support]):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;# hdparm -I /dev/sda&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; and look under &amp;quot;Enabled Supported&amp;quot; for &amp;quot;Write cache&amp;quot;&lt;br /&gt;
&lt;br /&gt;
For RAID controllers:&lt;br /&gt;
&lt;br /&gt;
* See the section about RAID controllers below&lt;br /&gt;
&lt;br /&gt;
== Q: How can I address the problem with the disk write cache? ==&lt;br /&gt;
&lt;br /&gt;
=== Disabling the disk write back cache. ===&lt;br /&gt;
&lt;br /&gt;
For SATA/PATA(IDE) (for SATA this requires at least kernel 2.6.15 because [http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=b095518ef51c37658c58367bd19240b8a113f25c ATA command passthrough support]):&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;# hdparm -W0 /dev/sda&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; # hdparm -W0 /dev/hda&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;# blktool /dev/sda wcache off&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; # blktool /dev/hda wcache off&lt;br /&gt;
&lt;br /&gt;
For SCSI:&lt;br /&gt;
&lt;br /&gt;
* Using sginfo(8) which is a little tedious&amp;lt;br /&amp;gt; It takes 3 steps. For example:&lt;br /&gt;
*# &amp;lt;nowiki&amp;gt;#sginfo -c /dev/sda&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; which gives a list of attribute names and values&lt;br /&gt;
*# &amp;lt;nowiki&amp;gt;#sginfo -cX /dev/sda&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; which gives an array of cache values which you must match up with from step 1, e.g.&amp;lt;br /&amp;gt; 0 0 0 1 0 1 0 0 0 0 65535 0 65535 65535 1 0 0 0 3 0 0&lt;br /&gt;
*# &amp;lt;nowiki&amp;gt;#sginfo -cXR /dev/sda 0 0 0 1 0 0 0 0 0 0 65535 0 65535 65535 1 0 0 0 3 0 0&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; allows you to reset the value of the cache attributes.&lt;br /&gt;
&lt;br /&gt;
For RAID controllers:&lt;br /&gt;
&lt;br /&gt;
* See the section about RAID controllers below&lt;br /&gt;
&lt;br /&gt;
This disabling is kept persistent for a SCSI disk. However, for a SATA/PATA disk this needs to be done after every reset as it will reset back to the default of the write cache enabled. And a reset can happen after reboot or on error recovery of the drive. This makes it rather difficult to guarantee that the write cache is maintained as disabled.&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using an external log. ===&lt;br /&gt;
&lt;br /&gt;
Some people have considered the idea of using an external log on a separate drive with the write cache disabled and the rest of the file system on another disk with the write cache enabled. However, that will &#039;&#039;&#039;not&#039;&#039;&#039; solve the problem. For example, the tail of the log is moved when we are notified that a metadata write is completed to disk and we won&#039;t be able to guarantee that if the metadata is on a drive with the write cache enabled.&lt;br /&gt;
&lt;br /&gt;
In fact using an external log will disable XFS&#039; write barrier support.&lt;br /&gt;
&lt;br /&gt;
=== Write barrier support. ===&lt;br /&gt;
&lt;br /&gt;
Write barrier support is enabled by default in XFS since kernel version 2.6.17. It is disabled by mounting the filesystem with &amp;quot;nobarrier&amp;quot;. Barrier support will flush the write back cache at the appropriate times (such as on XFS log writes). This is generally the recommended solution, however, you should check the system logs to ensure it was successful. Barriers will be disabled and reported in the log if any of the 3 scenarios occurs:&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;Disabling barriers, not supported with external log device&amp;quot;&lt;br /&gt;
* &amp;quot;Disabling barriers, not supported by the underlying device&amp;quot;&lt;br /&gt;
* &amp;quot;Disabling barriers, trial barrier write failed&amp;quot;&lt;br /&gt;
&lt;br /&gt;
If the filesystem is mounted with an external log device then we currently don&#039;t support flushing to the data and log devices (this may change in the future). If the driver tells the block layer that the device does not support write cache flushing with the write cache enabled then it will report that the device doesn&#039;t support it. And finally we will actually test out a barrier write on the superblock and test its error state afterwards, reporting if it fails.&lt;br /&gt;
&lt;br /&gt;
== Q. Should barriers be enabled with storage which has a persistent write cache? ==&lt;br /&gt;
&lt;br /&gt;
Many hardware RAID have a persistent write cache which preserves it across power failure, interface resets, system crashes, etc. Using write barriers in this instance is not recommended and will in fact lower performance. Therefore, it is recommended to turn off the barrier support and mount the filesystem with &amp;quot;nobarrier&amp;quot;, assuming your RAID controller is infallible and not resetting randomly like some common ones do.  But take care about the hard disk write cache, which should be off.&lt;br /&gt;
&lt;br /&gt;
== Q. Which settings does my RAID controller need ? ==&lt;br /&gt;
&lt;br /&gt;
It&#039;s hard to tell because there are so many controllers. Please consult your RAID controller documentation to determine how to change these settings, but we try to give an overview here:&lt;br /&gt;
&lt;br /&gt;
Real RAID controllers (not those found onboard of mainboards) normally have a battery or flash backed cache (or an [http://en.wikipedia.org/wiki/Electric_double-layer_capacitor ultracapacitor] + flash memory &amp;quot;[http://www.tweaktown.com/articles/2800/adaptec_zero_maintenance_cache_protection_explained/ zero maintenance cache]&amp;quot;) which is used for buffering writes to improve speed. This battery backed cache should ensure that if power fails or a PSU dies, the contents of the cache will be written to disk on next boot. However, the individual hard disk write caches need to be turned off, as they are not protected from a powerfail and will just lose all contents.&lt;br /&gt;
&lt;br /&gt;
If you do not have a battery or flash backed cache you should seriously consider disabling write cache if you value your data.&lt;br /&gt;
&lt;br /&gt;
* onboard RAID controllers: there are so many different types it&#039;s hard to tell. Generally, those controllers have no cache, but let the hard disk write cache on. That can lead to the bad situation that after a powerfail with RAID-1 when only parts of the disk cache have been written, the controller doesn&#039;t even see that the disks are out of sync, as the disks can resort cached blocks and might have saved the superblock info, but then lost different data contents. So, turn off disk write caches before using the RAID function.&lt;br /&gt;
&lt;br /&gt;
* 3ware: /cX/uX set cache=off, this will disable the controller and disk cache (see http://www.3ware.com/support/UserDocs/CLIGuide-9.5.1.1.pdf, page 86); &lt;br /&gt;
&lt;br /&gt;
* Adaptec: allows setting individual drives cache&lt;br /&gt;
arcconf setcache &amp;lt;disk&amp;gt; wb|wt&lt;br /&gt;
wb=write back, which means write cache on, wt=write through, which means write cache off. So &amp;quot;wt&amp;quot; should be chosen.&lt;br /&gt;
&lt;br /&gt;
* Areca: In archttp under &amp;quot;System Controls&amp;quot; -&amp;gt; &amp;quot;System Configuration&amp;quot; there&#039;s the option &amp;quot;Disk Write Cache Mode&amp;quot; (defaults &amp;quot;Auto&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Off&amp;quot;: disk write cache is turned off&lt;br /&gt;
&lt;br /&gt;
&amp;quot;On&amp;quot;: disk write cache is enabled, this is not safe for your data but fast&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Auto&amp;quot;: If you use a BBM (battery backup module, which you really should use if you care about your data), the controller automatically turns disk writes off, to protect your data. In case no BBM is attached, the controller switches to &amp;quot;On&amp;quot;, because neither controller cache nor disk cache is safe so you don&#039;t seem to care about your data and just want high speed (which you get then).&lt;br /&gt;
&lt;br /&gt;
That&#039;s a very sensible default so you can let it &amp;quot;Auto&amp;quot; or enforce &amp;quot;Off&amp;quot; to be sure.&lt;br /&gt;
&lt;br /&gt;
* LSI MegaRAID: allows setting individual disks cache:&lt;br /&gt;
 MegaCli -AdpCacheFlush -aN|-a0,1,2|-aALL                          # flushes the controller cache&lt;br /&gt;
 MegaCli -LDGetProp -Cache    -LN|-L0,1,2|-LAll -aN|-a0,1,2|-aALL  # shows the controller cache settings&lt;br /&gt;
 MegaCli -LDGetProp -DskCache -LN|-L0,1,2|-LAll -aN|-a0,1,2|-aALL  # shows the disk cache settings (for all phys. disks in logical disk)&lt;br /&gt;
 MegaCli -LDSetProp -EnDskCache|DisDskCache  -LN|-L0,1,2|-LAll  -aN|-a0,1,2|-aALL # set disk cache setting&lt;br /&gt;
&lt;br /&gt;
* Xyratex: from the docs: &amp;quot;Write cache includes the disk drive cache and controller cache.&amp;quot;. So that means you can only set the drive caches and the unit caches together. To protect your data, turn it off, but write performance will suffer badly as also the controller write cache is disabled.&lt;br /&gt;
&lt;br /&gt;
== Q: Which settings are best with virtualization like VMware, XEN, qemu? ==&lt;br /&gt;
&lt;br /&gt;
The biggest problem is that those products seem to also virtualize disk &lt;br /&gt;
writes in a way that even barriers don&#039;t work any more, which means even &lt;br /&gt;
a fsync is not reliable. Tests confirm that unplugging the power from &lt;br /&gt;
such a system even with RAID controller with battery backed cache and &lt;br /&gt;
hard disk cache turned off (which is safe on a normal host) you can &lt;br /&gt;
destroy a database within the virtual machine (client, domU whatever you &lt;br /&gt;
call it).&lt;br /&gt;
&lt;br /&gt;
In qemu you can specify cache=off on the line specifying the virtual &lt;br /&gt;
disk. For others information is missing.&lt;br /&gt;
&lt;br /&gt;
== Q: What is the issue with directory corruption in Linux 2.6.17? ==&lt;br /&gt;
&lt;br /&gt;
In the Linux kernel 2.6.17 release a subtle bug was accidentally introduced into the XFS directory code by some &amp;quot;sparse&amp;quot; endian annotations. This bug was sufficiently uncommon (it only affects a certain type of format change, in Node or B-Tree format directories, and only in certain situations) that it was not detected during our regular regression testing, but it has been observed in the wild by a number of people now.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Update: the fix is included in 2.6.17.7 and later kernels.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
To add insult to injury, &#039;&#039;&#039;xfs_repair(8)&#039;&#039;&#039; is currently not correcting these directories on detection of this corrupt state either. This &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; issue is actively being worked on, and a fixed version will be available shortly.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Update: a fixed &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; is now available; version 2.8.10 or later of the xfsprogs package contains the fixed version.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
No other kernel versions are affected. However, using a corrupt filesystem on other kernels can still result in the filesystem being shutdown if the problem has not been rectified (on disk), making it seem like other kernels are affected.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;xfs_repair -n&#039;&#039;&#039; should be able to detect any directory corruption.&lt;br /&gt;
&lt;br /&gt;
Until a fixed &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; binary is available, one can make use of the &#039;&#039;&#039;xfs_db(8)&#039;&#039;&#039; command to mark the problem directory for removal (see the example below). A subsequent &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; invocation will remove the directory and move all contents into &amp;quot;lost+found&amp;quot;, named by inode number (see second example on how to map inode number to directory entry name, which needs to be done _before_ removing the directory itself). The inode number of the corrupt directory is included in the shutdown report issued by the kernel on detection of directory corruption. Using that inode number, this is how one would ensure it is removed:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 # xfs_db -x /dev/sdXXX&lt;br /&gt;
 xfs_db&amp;amp;gt; inode NNN&lt;br /&gt;
 xfs_db&amp;amp;gt; print&lt;br /&gt;
 core.magic = 0x494e&lt;br /&gt;
 core.mode = 040755&lt;br /&gt;
 core.version = 2&lt;br /&gt;
 core.format = 3 (btree)&lt;br /&gt;
 ...&lt;br /&gt;
 xfs_db&amp;amp;gt; write core.mode 0&lt;br /&gt;
 xfs_db&amp;amp;gt; quit&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A subsequent &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; will clear the directory, and add new entries (named by inode number) in lost+found.&lt;br /&gt;
&lt;br /&gt;
The easiest way to map inode numbers to full paths is via &#039;&#039;&#039;xfs_ncheck(8)&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;: &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 # xfs_ncheck -i 14101 -i 14102 /dev/sdXXX&lt;br /&gt;
       14101 full/path/mumble_fratz_foo_bar_1495&lt;br /&gt;
       14102 full/path/mumble_fratz_foo_bar_1494&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Should this not work, we can manually map inode numbers in B-Tree format directory by taking the following steps:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 # xfs_db -x /dev/sdXXX&lt;br /&gt;
 xfs_db&amp;amp;gt; inode NNN&lt;br /&gt;
 xfs_db&amp;amp;gt; print&lt;br /&gt;
 core.magic = 0x494e&lt;br /&gt;
 ...&lt;br /&gt;
 next_unlinked = null&lt;br /&gt;
 u.bmbt.level = 1&lt;br /&gt;
 u.bmbt.numrecs = 1&lt;br /&gt;
 u.bmbt.keys[1] = [startoff] 1:[0]&lt;br /&gt;
 u.bmbt.ptrs[1] = 1:3628&lt;br /&gt;
 xfs_db&amp;amp;gt; fsblock 3628&lt;br /&gt;
 xfs_db&amp;amp;gt; type bmapbtd&lt;br /&gt;
 xfs_db&amp;amp;gt; print&lt;br /&gt;
 magic = 0x424d4150&lt;br /&gt;
 level = 0&lt;br /&gt;
 numrecs = 19&lt;br /&gt;
 leftsib = null&lt;br /&gt;
 rightsib = null&lt;br /&gt;
 recs[1-19] = [startoff,startblock,blockcount,extentflag]&lt;br /&gt;
        1:[0,3088,4,0] 2:[4,3128,8,0] 3:[12,3308,4,0] 4:[16,3360,4,0]&lt;br /&gt;
        5:[20,3496,8,0] 6:[28,3552,8,0] 7:[36,3624,4,0] 8:[40,3633,4,0]&lt;br /&gt;
        9:[44,3688,8,0] 10:[52,3744,4,0] 11:[56,3784,8,0]&lt;br /&gt;
        12:[64,3840,8,0] 13:[72,3896,4,0] 14:[33554432,3092,4,0]&lt;br /&gt;
        15:[33554436,3488,8,0] 16:[33554444,3629,4,0]&lt;br /&gt;
        17:[33554448,3748,4,0] 18:[33554452,3900,4,0]&lt;br /&gt;
        19:[67108864,3364,4,0]&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At this point we are looking at the extents that hold all of the directory information. There are three types of extent here, we have the data blocks (extents 1 through 13 above), then the leaf blocks (extents 14 through 18), then the freelist blocks (extent 19 above). The jumps in the first field (start offset) indicate our progression through each of the three types. For recovering file names, we are only interested in the data blocks, so we can now feed those offset numbers into the &#039;&#039;&#039;xfs_db&#039;&#039;&#039; dblock command. So, for the fifth extent - 5:[20,3496,8,0] - listed above:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
 xfs_db&amp;amp;gt; dblock 20&lt;br /&gt;
 xfs_db&amp;amp;gt; print&lt;br /&gt;
 dhdr.magic = 0x58443244&lt;br /&gt;
 dhdr.bestfree[0].offset = 0&lt;br /&gt;
 dhdr.bestfree[0].length = 0&lt;br /&gt;
 dhdr.bestfree[1].offset = 0&lt;br /&gt;
 dhdr.bestfree[1].length = 0&lt;br /&gt;
 dhdr.bestfree[2].offset = 0&lt;br /&gt;
 dhdr.bestfree[2].length = 0&lt;br /&gt;
 du[0].inumber = 13937&lt;br /&gt;
 du[0].namelen = 25&lt;br /&gt;
 du[0].name = &amp;quot;mumble_fratz_foo_bar_1595&amp;quot;&lt;br /&gt;
 du[0].tag = 0x10&lt;br /&gt;
 du[1].inumber = 13938&lt;br /&gt;
 du[1].namelen = 25&lt;br /&gt;
 du[1].name = &amp;quot;mumble_fratz_foo_bar_1594&amp;quot;&lt;br /&gt;
 du[1].tag = 0x38&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
So, here we can see that inode number 13938 matches up with name &amp;quot;mumble_fratz_foo_bar_1594&amp;quot;. Iterate through all the extents, and extract all the name-to-inode-number mappings you can, as these will be useful when looking at &amp;quot;lost+found&amp;quot; (once &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; has removed the corrupt directory).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Q: Why does my &amp;gt; 2TB XFS partition disappear when I reboot ? ==&lt;br /&gt;
&lt;br /&gt;
Strictly speaking this is not an XFS problem.&lt;br /&gt;
&lt;br /&gt;
To support &amp;gt; 2TB partitions you need two things: a kernel that supports large block devices (&amp;lt;tt&amp;gt;CONFIG_LBD=y&amp;lt;/tt&amp;gt;) and a partition table format that can hold large partitions.  The default DOS partition tables don&#039;t.  The best partition format for&lt;br /&gt;
&amp;gt; 2TB partitions is the EFI GPT format (&amp;lt;tt&amp;gt;CONFIG_EFI_PARTITION=y&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Without CONFIG_LBD=y you can&#039;t even create the filesystem, but without &amp;lt;tt&amp;gt;CONFIG_EFI_PARTITION=y&amp;lt;/tt&amp;gt; it works fine until you reboot at which point the partition will disappear.  Note that you need to enable the &amp;lt;tt&amp;gt;CONFIG_PARTITION_ADVANCED&amp;lt;/tt&amp;gt; option before you can set &amp;lt;tt&amp;gt;CONFIG_EFI_PARTITION=y&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Q: Why do I receive &amp;lt;tt&amp;gt;No space left on device&amp;lt;/tt&amp;gt; after &amp;lt;tt&amp;gt;xfs_growfs&amp;lt;/tt&amp;gt;? ==&lt;br /&gt;
&lt;br /&gt;
After [http://oss.sgi.com/pipermail/xfs/2009-January/039828.html growing a XFS filesystem], df(1) would show enough free space but attempts to write to the filesystem result in -ENOSPC. To fix this, [http://oss.sgi.com/pipermail/xfs/2009-January/039835.html Dave Chinner advised]:&lt;br /&gt;
&lt;br /&gt;
  The only way to fix this is to move data around to free up space&lt;br /&gt;
  below 1TB. Find your oldest data (i.e. that was around before even&lt;br /&gt;
  the first grow) and move it off the filesystem (move, not copy).&lt;br /&gt;
  Then if you copy it back on, the data blocks will end up above 1TB&lt;br /&gt;
  and that should leave you with plenty of space for inodes below 1TB.&lt;br /&gt;
  &lt;br /&gt;
  A complete dump and restore will also fix the problem ;)&lt;br /&gt;
&lt;br /&gt;
Also, you can add &#039;inode64&#039; to your mount options to allow inodes to live above 1TB.&lt;br /&gt;
&lt;br /&gt;
example:[https://www.centos.org/modules/newbb/viewtopic.php?topic_id=30703&amp;amp;forum=38 | No space left on device on xfs filesystem with 7.7TB free]&lt;br /&gt;
&lt;br /&gt;
== Q: Is using noatime or/and nodiratime at mount time giving any performance benefits in xfs (or not using them performance decrease)? ==&lt;br /&gt;
&lt;br /&gt;
The default atime behaviour is relatime, which has almost no overhead compared to noatime but still maintains sane atime values. All Linux filesystems use this as the default now (since around 2.6.30), but XFS has used relatime-like behaviour since 2006, so no-one should really need to ever use noatime on XFS for performance reasons. &lt;br /&gt;
&lt;br /&gt;
Also, noatime implies nodiratime, so there is never a need to specify nodiratime when noatime is also specified.&lt;br /&gt;
&lt;br /&gt;
== Q: How to get around a bad inode repair is unable to clean up ==&lt;br /&gt;
&lt;br /&gt;
The trick is go in with xfs_db and mark the inode as a deleted, which will cause repair to clean it up and finish the remove process.&lt;br /&gt;
&lt;br /&gt;
  xfs_db -x -c &#039;inode XXX&#039; -c &#039;write core.nextents 0&#039; -c &#039;write core.size 0&#039; /dev/hdXX&lt;br /&gt;
&lt;br /&gt;
== Q: How to calculate the correct sunit,swidth values for optimal performance ==&lt;br /&gt;
&lt;br /&gt;
XFS allows to optimize for a given RAID stripe unit (stripe size) and stripe width (number of data disks) via mount options.&lt;br /&gt;
&lt;br /&gt;
These options can be sometimes autodetected (for example with md raid and recent enough kernel (&amp;gt;= 2.6.32) and xfsprogs (&amp;gt;= 3.1.1) built with libblkid support) but manual calculation is needed for most of hardware raids.&lt;br /&gt;
&lt;br /&gt;
The calculation of these values is quite simple:&lt;br /&gt;
&lt;br /&gt;
  su = &amp;lt;RAID controllers stripe size in BYTES (or KiBytes when used with k)&amp;gt;&lt;br /&gt;
  sw = &amp;lt;# of data disks (don&#039;t count parity disks)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So if your RAID controller has a stripe size of 64KB, and you have a RAID-6 with 8 disks, use&lt;br /&gt;
&lt;br /&gt;
  su = 64k&lt;br /&gt;
  sw = 6 (RAID-6 of 8 disks has 6 data disks)&lt;br /&gt;
&lt;br /&gt;
A RAID stripe size of 256KB with a RAID-10 over 16 disks should use&lt;br /&gt;
&lt;br /&gt;
  su = 256k&lt;br /&gt;
  sw = 8 (RAID-10 of 16 disks has 8 data disks)&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can use &amp;quot;sunit&amp;quot; instead of &amp;quot;su&amp;quot; and &amp;quot;swidth&amp;quot; instead of &amp;quot;sw&amp;quot; but then sunit/swidth values need to be specified in &amp;quot;number of 512B sectors&amp;quot;!&lt;br /&gt;
&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;xfs_info&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;mkfs.xfs&amp;lt;/tt&amp;gt; interpret sunit and swidth as being specified in units of 512B sectors; that&#039;s unfortunately not the unit they&#039;re reported in, however.&lt;br /&gt;
&amp;lt;tt&amp;gt;xfs_info&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;mkfs.xfs&amp;lt;/tt&amp;gt; report them in multiples of your basic block size (bsize) and not in 512B sectors.&lt;br /&gt;
&lt;br /&gt;
Assume for example: swidth 1024 (specified at mkfs.xfs command line; so 1024 of 512B sectors) and block size of 4096 (bsize reported by mkfs.xfs at output). You should see swidth 128 (reported by mkfs.xfs at output). 128 * 4096 == 1024 * 512.&lt;br /&gt;
&lt;br /&gt;
When creating XFS filesystem on top of LVM on top of hardware raid please use sunit/swith values as when creating XFS filesystem directly on top of hardware raid.&lt;br /&gt;
&lt;br /&gt;
== Q: Why doesn&#039;t NFS-exporting subdirectories of inode64-mounted filesystem work? ==&lt;br /&gt;
&lt;br /&gt;
The default &amp;lt;tt&amp;gt;fsid&amp;lt;/tt&amp;gt; type encodes only 32-bit of the inode number for subdirectory exports.  However, exporting the root of the filesystem works, or using one of the non-default &amp;lt;tt&amp;gt;fsid&amp;lt;/tt&amp;gt; types (&amp;lt;tt&amp;gt;fsid=uuid&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;/etc/exports&amp;lt;/tt&amp;gt; with recent &amp;lt;tt&amp;gt;nfs-utils&amp;lt;/tt&amp;gt;) should work as well. (Thanks, Christoph!)&lt;br /&gt;
&lt;br /&gt;
== Q: What is the inode64 mount option for? ==&lt;br /&gt;
&lt;br /&gt;
By default, with 32bit inodes, XFS places inodes only in the first 1TB of a disk. If you have a disk with 100TB, all inodes will be stuck in the first TB. This can lead to strange things like &amp;quot;disk full&amp;quot; when you still have plenty space free, but there&#039;s no more place in the first TB to create a new inode. Also, performance sucks.&lt;br /&gt;
&lt;br /&gt;
To come around this, use the inode64 mount options for filesystems &amp;gt;1TB. Inodes will then be placed in the location where their data is, minimizing disk seeks.&lt;br /&gt;
&lt;br /&gt;
Beware that some old programs might have problems reading 64bit inodes, especially over NFS. Your editor used inode64 for over a year with recent (openSUSE 11.1 and higher) distributions using NFS and Samba without any corruptions, so that might be a recent enough distro.&lt;br /&gt;
&lt;br /&gt;
== Q: Can I just try the inode64 option to see if it helps me? ==&lt;br /&gt;
&lt;br /&gt;
Starting from kernel 2.6.35, you can try and then switch back. Older kernels have a bug leading to strange problems if you mount without inode64 again. For example, you can&#039;t access files &amp;amp; dirs that have been created with an inode &amp;gt;32bit anymore.&lt;br /&gt;
&lt;br /&gt;
== Q: Performance: mkfs.xfs -n size=64k option ==&lt;br /&gt;
&lt;br /&gt;
Asking the implications of that mkfs option on the XFS mailing list, Dave Chinner explained it this way:&lt;br /&gt;
&lt;br /&gt;
Inodes are not stored in the directory structure, only the directory entry name and the inode number. Hence the amount of space used by a&lt;br /&gt;
directory entry is determined by the length of the name.&lt;br /&gt;
&lt;br /&gt;
There is extra overhead to allocate large directory blocks (16 pages instead of one, to begin with, then there&#039;s the vmap overhead, etc), so for small directories smaller block sizes are faster for create and unlink operations.&lt;br /&gt;
&lt;br /&gt;
For empty directories, operations on 4k block sized directories consume roughly 50% less CPU that 64k block size directories. The 4k block size directories consume less CPU out to roughly 1.5 million entries where the two are roughly equal. At directory sizes of 10 million entries, 64k directory block operations are consuming about 15% of the CPU that 4k directory block operations consume.&lt;br /&gt;
&lt;br /&gt;
In terms of lookups, the 64k block directory will take less IO but consume more CPU for a given lookup. Hence it depends on your IO latency and whether directory readahead can hide that latency as to which will be faster. e.g. For SSDs, CPU usage might be the limiting factor, not the IO. Right now I don&#039;t have any numbers on what the difference might be - I&#039;m getting 1 billion inode population issues worked out first before I start on measuring cold cache lookup times on 1 billion files....&lt;br /&gt;
&lt;br /&gt;
== Q: I want to tune my XFS filesystems for &amp;lt;something&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Premature optimization is the root of all evil.&#039;&#039; - Donald Knuth&lt;br /&gt;
&lt;br /&gt;
The standard answer you will get to this question is this: use the defaults.&lt;br /&gt;
&lt;br /&gt;
There are few workloads where using non-default mkfs.xfs or mount options make much sense. In general, the default values already used are optimised for best performance in the first place. mkfs.xfs will detect the difference between single disk and MD/DM RAID setups and change the default values it uses to  configure the filesystem appropriately.&lt;br /&gt;
&lt;br /&gt;
There are a lot of &amp;quot;XFS tuning guides&amp;quot; that Google will find for you - most are old, out of date and full of misleading or just plain incorrect information. Don&#039;t expect that tuning your filesystem for optimal bonnie++ numbers will mean your workload will go faster. You should only consider changing the defaults if either: a) you know from experience that your workload causes XFS a specific problem that can be worked around via a configuration change, or b) your workload is demonstrating bad performance when using the default configurations. In this case, you need to understand why your application is causing bad performance before you start tweaking XFS configurations.&lt;br /&gt;
&lt;br /&gt;
In most cases, the only thing you need to to consider for &amp;lt;tt&amp;gt;mkfs.xfs&amp;lt;/tt&amp;gt; is specifying the stripe unit and width for hardware RAID devices. For mount options, the only thing that will change metadata performance considerably are the &amp;lt;tt&amp;gt;logbsize&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;delaylog&amp;lt;/tt&amp;gt; mount options. Increasing &amp;lt;tt&amp;gt;logbsize&amp;lt;/tt&amp;gt; reduces the number of journal IOs for a given workload, and &amp;lt;tt&amp;gt;delaylog&amp;lt;/tt&amp;gt; will reduce them even further. The trade off for this increase in metadata performance is that more operations may be &amp;quot;missing&amp;quot; after recovery if the system crashes while actively making modifications.&lt;br /&gt;
&lt;br /&gt;
As of kernel 3.2.12, the default i/o scheduler, CFQ, will defeat much of the parallelization in XFS.&lt;br /&gt;
&lt;br /&gt;
== Q: Which factors influence the memory usage of xfs_repair? ==&lt;br /&gt;
&lt;br /&gt;
This is best explained with an example. The example filesystem is 16Tb, but basically empty (look at icount).&lt;br /&gt;
&lt;br /&gt;
  # xfs_repair -n -vv -m 1 /dev/vda&lt;br /&gt;
  Phase 1 - find and verify superblock...&lt;br /&gt;
          - max_mem = 1024, icount = 64, imem = 0, dblock = 4294967296, dmem = 2097152&lt;br /&gt;
  Required memory for repair is greater that the maximum specified&lt;br /&gt;
  with the -m option. Please increase it to at least 2096.&lt;br /&gt;
  #&lt;br /&gt;
&lt;br /&gt;
xfs_repair is saying it needs at least 2096MB of RAM to repair the filesystem,&lt;br /&gt;
of which 2,097,152KB is needed for tracking free space. &lt;br /&gt;
(The -m 1 argument was telling xfs_repair to use ony 1 MB of memory.)&lt;br /&gt;
&lt;br /&gt;
Now if we add some inodes (50 million) to the filesystem (look at icount again), and the result is:&lt;br /&gt;
&lt;br /&gt;
  # xfs_repair -vv -m 1 /dev/vda&lt;br /&gt;
  Phase 1 - find and verify superblock...&lt;br /&gt;
          - max_mem = 1024, icount = 50401792, imem = 196882, dblock = 4294967296, dmem = 2097152&lt;br /&gt;
  Required memory for repair is greater that the maximum specified&lt;br /&gt;
  with the -m option. Please increase it to at least 2289.&lt;br /&gt;
&lt;br /&gt;
That is now needs at least another 200MB of RAM to run.&lt;br /&gt;
&lt;br /&gt;
The numbers reported by xfs_repair are the absolute minimum required and approximate at that;&lt;br /&gt;
more RAM than this may be required to complete successfully.&lt;br /&gt;
Also, if you only give xfs_repair the minimum required RAM, it will be slow;&lt;br /&gt;
for best repair performance, the more RAM you can give it the better.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Q: Why some files of my filesystem shows as &amp;quot;?????????? ? ?      ?          ?                ? filename&amp;quot; ? ==&lt;br /&gt;
&lt;br /&gt;
If ls -l shows you a listing as&lt;br /&gt;
&lt;br /&gt;
  # ?????????? ? ?      ?          ?                ? file1&lt;br /&gt;
    ?????????? ? ?      ?          ?                ? file2&lt;br /&gt;
    ?????????? ? ?      ?          ?                ? file3&lt;br /&gt;
    ?????????? ? ?      ?          ?                ? file4&lt;br /&gt;
&lt;br /&gt;
and errors like:&lt;br /&gt;
  # ls /pathtodir/&lt;br /&gt;
    ls: cannot access /pathtodir/file1: Invalid argument&lt;br /&gt;
    ls: cannot access /pathtodir/file2: Invalid argument&lt;br /&gt;
    ls: cannot access /pathtodir/file3: Invalid argument&lt;br /&gt;
    ls: cannot access /pathtodir/file4: Invalid argument&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
or even:&lt;br /&gt;
  # failed to stat /pathtodir/file1&lt;br /&gt;
&lt;br /&gt;
It is very probable your filesystem must be mounted with inode64&lt;br /&gt;
  # mount -oremount,inode64 /dev/diskpart /mnt/xfs&lt;br /&gt;
&lt;br /&gt;
should make it work ok again.&lt;br /&gt;
If it works, add the option to fstab.&lt;br /&gt;
&lt;br /&gt;
== Q: The xfs_db &amp;quot;frag&amp;quot; command says I&#039;m over 50%.  Is that bad? ==&lt;br /&gt;
&lt;br /&gt;
It depends.  It&#039;s important to know how the value is calculated.  xfs_db looks at the extents in all files, and returns:&lt;br /&gt;
&lt;br /&gt;
  (actual extents - ideal extents) / actual extents&lt;br /&gt;
&lt;br /&gt;
This means that if, for example, you have an average of 2 extents per file, you&#039;ll get an answer of 50%.  4 extents per file would give you 75%.  This may or may not be a problem, especially depending on the size of the files in question.  (i.e. 400GB files in four 100GB extents would hardly be considered badly fragmented).  The xfs_bmap command can be useful for displaying the actual fragmentation/layout of individual files.&lt;br /&gt;
&lt;br /&gt;
Note that above a few average extents per file, the fragmentation factor rapidly approaches 100%:&lt;br /&gt;
[[Image:Frag_factor.png|500px]]&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=XFS_FAQ&amp;diff=2488</id>
		<title>XFS FAQ</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=XFS_FAQ&amp;diff=2488"/>
		<updated>2012-04-27T10:12:27Z</updated>

		<summary type="html">&lt;p&gt;Dgc: updated trace-cmd directions.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Info from: [http://oss.sgi.com/projects/xfs/faq.html main XFS faq at SGI]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Many thanks to earlier maintainers of this document - Thomas Graichen and Seth Mos.&lt;br /&gt;
&lt;br /&gt;
== Q: Where can I find documentation about XFS? ==&lt;br /&gt;
&lt;br /&gt;
The SGI XFS project page http://oss.sgi.com/projects/xfs/ is the definitive reference. It contains pointers to whitepapers, books, articles, etc.&lt;br /&gt;
&lt;br /&gt;
You could also join the [[XFS_email_list_and_archives|XFS mailing list]] or the &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;#xfs&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039; IRC channel on &#039;&#039;irc.freenode.net&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Q: Where can I find documentation about ACLs? ==&lt;br /&gt;
&lt;br /&gt;
Andreas Gruenbacher maintains the Extended Attribute and POSIX ACL documentation for Linux at http://acl.bestbits.at/&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;acl(5)&#039;&#039;&#039; manual page is also quite extensive.&lt;br /&gt;
&lt;br /&gt;
== Q: Where can I find information about the internals of XFS? ==&lt;br /&gt;
&lt;br /&gt;
An [http://oss.sgi.com/projects/xfs/training/ SGI XFS Training course] aimed at developers, triage and support staff, and serious users has been in development. Parts of the course are clearly still incomplete, but there is enough content to be useful to a broad range of users.&lt;br /&gt;
&lt;br /&gt;
Barry Naujok has documented the [http://oss.sgi.com/projects/xfs/papers/xfs_filesystem_structure.pdf XFS ondisk format] which is a very useful reference.&lt;br /&gt;
&lt;br /&gt;
== Q: What partition type should I use for XFS on Linux? ==&lt;br /&gt;
&lt;br /&gt;
Linux native filesystem (83).&lt;br /&gt;
&lt;br /&gt;
== Q: What mount options does XFS have? ==&lt;br /&gt;
&lt;br /&gt;
There are a number of mount options influencing XFS filesystems - refer to the &#039;&#039;&#039;mount(8)&#039;&#039;&#039; manual page or the documentation in the kernel source tree itself ([http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/filesystems/xfs.txt;hb=HEAD Documentation/filesystems/xfs.txt])&lt;br /&gt;
&lt;br /&gt;
== Q: Is there any relation between the XFS utilities and the kernel version? ==&lt;br /&gt;
&lt;br /&gt;
No, there is no relation. Newer utilities tend to mainly have fixes and checks the previous versions might not have. New features are also added in a backward compatible way - if they are enabled via mkfs, an incapable (old) kernel will recognize that it does not understand the new feature, and refuse to mount the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Q: Does it run on platforms other than i386? ==&lt;br /&gt;
&lt;br /&gt;
XFS runs on all of the platforms that Linux supports. It is more tested on the more common platforms, especially the i386 family. Its also well tested on the IA64 platform since thats the platform SGI Linux products use.&lt;br /&gt;
&lt;br /&gt;
== Q: Quota: Do quotas work on XFS? ==&lt;br /&gt;
&lt;br /&gt;
Yes.&lt;br /&gt;
&lt;br /&gt;
To use quotas with XFS, you need to enable XFS quota support when you configure your kernel. You also need to specify quota support when mounting. You can get the Linux quota utilities at their sourceforge website [http://sourceforge.net/projects/linuxquota/  http://sourceforge.net/projects/linuxquota/] or use &#039;&#039;&#039;xfs_quota(8)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Q: Quota: What&#039;s project quota? ==&lt;br /&gt;
&lt;br /&gt;
The  project  quota  is a quota mechanism in XFS can be used to implement a form of directory tree quota, where a specified directory and all of the files and subdirectories below it (i.e. a tree) can be restricted to using a subset of the available space in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Q: Quota: Can group quota and project quota be used at the same time? ==&lt;br /&gt;
&lt;br /&gt;
No, project quota cannot be used with group quota at the same time. On the other hand user quota and project quota can be used simultaneously.&lt;br /&gt;
&lt;br /&gt;
== Q: Quota: Is umounting prjquota (project quota) enabled fs and mounting it again with grpquota (group quota) removing prjquota limits previously set from fs (and vice versa) ? ==&lt;br /&gt;
&lt;br /&gt;
To be answered.&lt;br /&gt;
&lt;br /&gt;
== Q: Are there any dump/restore tools for XFS? ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;xfsdump(8)&#039;&#039;&#039; and &#039;&#039;&#039;xfsrestore(8)&#039;&#039;&#039; are fully supported. The tape format is the same as on IRIX, so tapes are interchangeable between operating systems.&lt;br /&gt;
&lt;br /&gt;
== Q: Does LILO work with XFS? ==&lt;br /&gt;
&lt;br /&gt;
This depends on where you install LILO.&lt;br /&gt;
&lt;br /&gt;
Yes, for MBR (Master Boot Record) installations.&lt;br /&gt;
&lt;br /&gt;
No, for root partition installations because the XFS superblock is written at block zero, where LILO would be installed. This is to maintain compatibility with the IRIX on-disk format, and will not be changed.&lt;br /&gt;
&lt;br /&gt;
== Q: Does GRUB work with XFS? ==&lt;br /&gt;
&lt;br /&gt;
There is native XFS filesystem support for GRUB starting with version 0.91 and onward. Unfortunately, GRUB used to make incorrect assumptions about being able to read a block device image while a filesystem is mounted and actively being written to, which could cause intermittent problems when using XFS. This has reportedly since been fixed, and the 0.97 version (at least) of GRUB is apparently stable.&lt;br /&gt;
&lt;br /&gt;
== Q: Can XFS be used for a root filesystem? ==&lt;br /&gt;
&lt;br /&gt;
Yes, with one caveat: Linux does not support an external XFS journal for the root filesystem via the &amp;quot;rootflags=&amp;quot; kernel parameter. To use an external journal for the root filesystem in Linux, an init ramdisk must mount the root filesystem with explicit &amp;quot;logdev=&amp;quot; specified. [http://mindplusplus.wordpress.com/2008/07/27/scratching-an-i.html More information here.]&lt;br /&gt;
&lt;br /&gt;
== Q: Will I be able to use my IRIX XFS filesystems on Linux? ==&lt;br /&gt;
&lt;br /&gt;
Yes. The on-disk format of XFS is the same on IRIX and Linux. Obviously, you should back-up your data before trying to move it between systems. Filesystems must be &amp;quot;clean&amp;quot; when moved (i.e. unmounted). If you plan to use IRIX filesystems on Linux keep the following points in mind: the kernel needs to have SGI partition support enabled; there is no XLV support in Linux, so you are unable to read IRIX filesystems which use the XLV volume manager; also not all blocksizes available on IRIX are available on Linux (only blocksizes less than or equal to the pagesize of the architecture: 4k for i386, ppc, ... 8k for alpha, sparc, ... is possible for now). Make sure that the directory format is version 2 on the IRIX filesystems (this is the default since IRIX 6.5.5). Linux can only read v2 directories.&lt;br /&gt;
&lt;br /&gt;
== Q: Is there a way to make a XFS filesystem larger or smaller? ==&lt;br /&gt;
&lt;br /&gt;
You can &#039;&#039;NOT&#039;&#039; make a XFS partition smaller online. The only way to shrink is to do a complete dump, mkfs and restore.&lt;br /&gt;
&lt;br /&gt;
An XFS filesystem may be enlarged by using &#039;&#039;&#039;xfs_growfs(8)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
If using partitions, you need to have free space after this partition to do so. Remove partition, recreate it larger with the &#039;&#039;exact same&#039;&#039; starting point. Run &#039;&#039;&#039;xfs_growfs&#039;&#039;&#039; to make the partition larger. Note - editing partition tables is a dangerous pastime, so back up your filesystem before doing so.&lt;br /&gt;
&lt;br /&gt;
Using XFS filesystems on top of a volume manager makes this a lot easier.&lt;br /&gt;
&lt;br /&gt;
== Q: What information should I include when reporting a problem? ==&lt;br /&gt;
&lt;br /&gt;
What you need to report depend on the problem you are seeing. Firstly, your machine hardware and storage configuration needs to be described. That includes:&lt;br /&gt;
&lt;br /&gt;
* kernel version (uname -a)&lt;br /&gt;
* xfsprogs version (xfs_repair -V)&lt;br /&gt;
* number of CPUs&lt;br /&gt;
* contents of /proc/meminfo&lt;br /&gt;
* contents of /proc/mounts&lt;br /&gt;
* contents of /proc/partitions&lt;br /&gt;
* RAID layout (hardware and/or software)&lt;br /&gt;
* LVM configuration&lt;br /&gt;
* type of disks you are using&lt;br /&gt;
* write cache status of drives&lt;br /&gt;
* size of BBWC and mode it is running in&lt;br /&gt;
* xfs_info output on the filesystem in question&lt;br /&gt;
* dmesg output showing all error messages and stack traces&lt;br /&gt;
 &lt;br /&gt;
Then you need to describe your workload that is causing the problem, and a demonstration of the bad behaviour that is occurring. If it is a performance problem, then 30s - 1 minute samples of:&lt;br /&gt;
&lt;br /&gt;
# iostat -x -d -m 5&lt;br /&gt;
# vmstat 5&lt;br /&gt;
 &lt;br /&gt;
can give us insight into the IO and memory utilisation of your machine at the time of the problem.&lt;br /&gt;
&lt;br /&gt;
If the filesystem is hanging, then capture the output of the dmesg command after running:&lt;br /&gt;
&lt;br /&gt;
 # echo w &amp;gt; /proc/sysrq-trigger&lt;br /&gt;
 # dmesg&lt;br /&gt;
&lt;br /&gt;
will tell us all the hung processes in the machine, often pointing us directly to the cause of the hang.&lt;br /&gt;
&lt;br /&gt;
And for advanced users, capturing an event trace using &#039;&#039;&#039;trace-cmd&#039;&#039;&#039; (git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/trace-cmd.git) will be very helpful. In many cases the XFS developers will ask for this information anyway, so it&#039;s a good idea to be ready with it in advance. Start the trace with this command, either from a directory not on an XFS filesystem or with an output file destination on a non-XFS filesystem:&lt;br /&gt;
&lt;br /&gt;
 # trace-cmd record -e xfs\*&lt;br /&gt;
&lt;br /&gt;
before the problem occurs, and once it has occurred, kill the trace-cmd with ctrl-C, and then run:&lt;br /&gt;
&lt;br /&gt;
 # trace-cmd report &amp;gt; trace_report.txt&lt;br /&gt;
&lt;br /&gt;
Compress the trace_report.txt file and include that with the bug report. The reason for trying to host the output of the record command on a different filesystem is so that the writing of the output file does not pollute the trace of the problem we are trying to diagnose.&lt;br /&gt;
&lt;br /&gt;
If you have a problem with &#039;&#039;&#039;xfs_repair(8)&#039;&#039;&#039;, make sure that you save the entire output of the problematic run so that the developers can see exactly where it encountered the problem. You might be asked to capture the metadata in the filesystem using &#039;&#039;&#039;xfs_metadump(8)&#039;&#039;&#039; (which obfuscates filenames and attributes to protect your privacy) and make the dump available for someone to analyse.&lt;br /&gt;
&lt;br /&gt;
== Q: Mounting an XFS filesystem does not work - what is wrong? ==&lt;br /&gt;
&lt;br /&gt;
If mount prints an error message something like:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
     mount: /dev/hda5 has wrong major or minor number&lt;br /&gt;
&lt;br /&gt;
you either do not have XFS compiled into the kernel (or you forgot to load the modules) or you did not use the &amp;quot;-t xfs&amp;quot; option on mount or the &amp;quot;xfs&amp;quot; option in &amp;lt;tt&amp;gt;/etc/fstab&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you get something like:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 mount: wrong fs type, bad option, bad superblock on /dev/sda1,&lt;br /&gt;
        or too many mounted file systems&lt;br /&gt;
&lt;br /&gt;
Refer to your system log file (&amp;lt;tt&amp;gt;/var/log/messages&amp;lt;/tt&amp;gt;) for a detailed diagnostic message from the kernel.&lt;br /&gt;
&lt;br /&gt;
== Q: Does the filesystem have an undelete capability? ==&lt;br /&gt;
&lt;br /&gt;
There is no undelete in XFS (so far).&lt;br /&gt;
&lt;br /&gt;
However at least some XFS driver implementations do not wipe file information nodes completely so there are chance to recover files with specialized commercial closed source software like [http://www.ufsexplorer.com/rdr_xfs.php Raise Data Recovery for XFS].&lt;br /&gt;
&lt;br /&gt;
In this kind of XFS driver implementation it does not re-use directory entries immediately so there are chance to get back recently deleted files even with their real names.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;xfs_irecover&#039;&#039; or &#039;&#039;xfsr&#039;&#039; may help too, [http://www.who.is.free.fr/wiki/doku.php?id=recover this site] has a few links.&lt;br /&gt;
&lt;br /&gt;
This applies to most recent Linux distributions (versions?), as well as to most popular NAS boxes that use embedded linux and XFS file system.&lt;br /&gt;
&lt;br /&gt;
Anyway, the best is to always keep backups.&lt;br /&gt;
&lt;br /&gt;
== Q: How can I backup a XFS filesystem and ACLs? ==&lt;br /&gt;
&lt;br /&gt;
You can backup a XFS filesystem with utilities like &#039;&#039;&#039;xfsdump(8)&#039;&#039;&#039; and standard &#039;&#039;&#039;tar(1)&#039;&#039;&#039; for standard files. If you want to backup ACLs you will need to use &#039;&#039;&#039;xfsdump&#039;&#039;&#039; or [http://www.bacula.org/en/dev-manual/Current_State_Bacula.html Bacula] (&amp;gt; version 3.1.4) or [http://rsync.samba.org/ rsync] (&amp;gt;= version 3.0.0) to backup ACLs and EAs. &#039;&#039;&#039;xfsdump&#039;&#039;&#039; can also be integrated with [http://www.amanda.org/ amanda(8)].&lt;br /&gt;
&lt;br /&gt;
== Q: I see applications returning error 990 or &amp;quot;Structure needs cleaning&amp;quot;, what is wrong? ==&lt;br /&gt;
&lt;br /&gt;
The error 990 stands for [http://oss.sgi.com/cgi-bin/gitweb.cgi?p=xfs/xfs.git;a=blob;f=fs/xfs/linux-2.6/xfs_linux.h#l145 EFSCORRUPTED] which usually means XFS has detected a filesystem metadata problem and has shut the filesystem down to prevent further damage. Also, since about June 2006, we [http://oss.sgi.com/cgi-bin/gitweb.cgi?p=xfs/xfs.git;a=commit;h=da2f4d679c8070ba5b6a920281e495917b293aa0 converted from EFSCORRUPTED/990 over to using EUCLEAN], &amp;quot;Structure needs cleaning.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The cause can be pretty much anything, unfortunately - filesystem, virtual memory manager, volume manager, device driver, or hardware.&lt;br /&gt;
&lt;br /&gt;
There should be a detailed console message when this initially happens. The messages have important information giving hints to developers as to the earliest point that a problem was detected. It is there to protect your data.&lt;br /&gt;
&lt;br /&gt;
You can use xfs_check and xfs_repair to remedy the problem (with the file system unmounted).&lt;br /&gt;
&lt;br /&gt;
== Q: Why do I see binary NULLS in some files after recovery when I unplugged the power? ==&lt;br /&gt;
&lt;br /&gt;
Update: This issue has been addressed with a CVS fix on the 29th March 2007 and merged into mainline on 8th May 2007 for 2.6.22-rc1.&lt;br /&gt;
&lt;br /&gt;
XFS journals metadata updates, not data updates. After a crash you are supposed to get a consistent filesystem which looks like the state sometime shortly before the crash, NOT what the in memory image looked like the instant before the crash.&lt;br /&gt;
&lt;br /&gt;
Since XFS does not write data out immediately unless you tell it to with fsync, an O_SYNC or O_DIRECT open (the same is true of other filesystems), you are looking at an inode which was flushed out, but whose data was not. Typically you&#039;ll find that the inode is not taking any space since all it has is a size but no extents allocated (try examining the file with the &#039;&#039;&#039;xfs_bmap(8)&#039;&#039;&#039; command).&lt;br /&gt;
&lt;br /&gt;
== Q: What is the problem with the write cache on journaled filesystems? ==&lt;br /&gt;
&lt;br /&gt;
Many drives use a write back cache in order to speed up the performance of writes.  However, there are conditions such as power failure when the write cache memory is never flushed to the actual disk.  Further, the drive can de-stage data from the write cache to the platters in any order that it chooses.  This causes problems for XFS and journaled filesystems in general because they rely on knowing when a write has completed to the disk. They need to know that the log information has made it to disk before allowing metadata to go to disk.  When the metadata makes it to disk then the transaction can effectively be deleted from the log resulting in movement of the tail of the log and thus freeing up some log space. So if the writes never make it to the physical disk, then the ordering is violated and the log and metadata can be lost, resulting in filesystem corruption.&lt;br /&gt;
&lt;br /&gt;
With hard disk cache sizes of currently (Jan 2009) up to 32MB that can be a lot of valuable information.  In a RAID with 8 such disks these adds to 256MB, and the chance of having filesystem metadata in the cache is so high that you have a very high chance of big data losses on a power outage.&lt;br /&gt;
&lt;br /&gt;
With a single hard disk and barriers turned on (on=default), the drive write cache is flushed before and after a barrier is issued.  A powerfail &amp;quot;only&amp;quot; loses data in the cache but no essential ordering is violated, and corruption will not occur.&lt;br /&gt;
&lt;br /&gt;
With a RAID controller with battery backed controller cache and cache in write back mode, you should turn off barriers - they are unnecessary in this case, and if the controller honors the cache flushes, it will be harmful to performance.  But then you *must* disable the individual hard disk write cache in order to ensure to keep the filesystem intact after a power failure. The method for doing this is different for each RAID controller. See the section about RAID controllers below.&lt;br /&gt;
&lt;br /&gt;
== Q: How can I tell if I have the disk write cache enabled? ==&lt;br /&gt;
&lt;br /&gt;
For SCSI/SATA:&lt;br /&gt;
&lt;br /&gt;
* Look in dmesg(8) output for a driver line, such as:&amp;lt;br /&amp;gt; &amp;quot;SCSI device sda: drive cache: write back&amp;quot;&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;# sginfo -c /dev/sda | grep -i &#039;write cache&#039; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For PATA/SATA (for SATA this requires at least kernel 2.6.15 because [http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=b095518ef51c37658c58367bd19240b8a113f25c ATA command passthrough support]):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;# hdparm -I /dev/sda&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; and look under &amp;quot;Enabled Supported&amp;quot; for &amp;quot;Write cache&amp;quot;&lt;br /&gt;
&lt;br /&gt;
For RAID controllers:&lt;br /&gt;
&lt;br /&gt;
* See the section about RAID controllers below&lt;br /&gt;
&lt;br /&gt;
== Q: How can I address the problem with the disk write cache? ==&lt;br /&gt;
&lt;br /&gt;
=== Disabling the disk write back cache. ===&lt;br /&gt;
&lt;br /&gt;
For SATA/PATA(IDE) (for SATA this requires at least kernel 2.6.15 because [http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=b095518ef51c37658c58367bd19240b8a113f25c ATA command passthrough support]):&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;# hdparm -W0 /dev/sda&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; # hdparm -W0 /dev/hda&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;# blktool /dev/sda wcache off&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; # blktool /dev/hda wcache off&lt;br /&gt;
&lt;br /&gt;
For SCSI:&lt;br /&gt;
&lt;br /&gt;
* Using sginfo(8) which is a little tedious&amp;lt;br /&amp;gt; It takes 3 steps. For example:&lt;br /&gt;
*# &amp;lt;nowiki&amp;gt;#sginfo -c /dev/sda&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; which gives a list of attribute names and values&lt;br /&gt;
*# &amp;lt;nowiki&amp;gt;#sginfo -cX /dev/sda&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; which gives an array of cache values which you must match up with from step 1, e.g.&amp;lt;br /&amp;gt; 0 0 0 1 0 1 0 0 0 0 65535 0 65535 65535 1 0 0 0 3 0 0&lt;br /&gt;
*# &amp;lt;nowiki&amp;gt;#sginfo -cXR /dev/sda 0 0 0 1 0 0 0 0 0 0 65535 0 65535 65535 1 0 0 0 3 0 0&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; allows you to reset the value of the cache attributes.&lt;br /&gt;
&lt;br /&gt;
For RAID controllers:&lt;br /&gt;
&lt;br /&gt;
* See the section about RAID controllers below&lt;br /&gt;
&lt;br /&gt;
This disabling is kept persistent for a SCSI disk. However, for a SATA/PATA disk this needs to be done after every reset as it will reset back to the default of the write cache enabled. And a reset can happen after reboot or on error recovery of the drive. This makes it rather difficult to guarantee that the write cache is maintained as disabled.&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using an external log. ===&lt;br /&gt;
&lt;br /&gt;
Some people have considered the idea of using an external log on a separate drive with the write cache disabled and the rest of the file system on another disk with the write cache enabled. However, that will &#039;&#039;&#039;not&#039;&#039;&#039; solve the problem. For example, the tail of the log is moved when we are notified that a metadata write is completed to disk and we won&#039;t be able to guarantee that if the metadata is on a drive with the write cache enabled.&lt;br /&gt;
&lt;br /&gt;
In fact using an external log will disable XFS&#039; write barrier support.&lt;br /&gt;
&lt;br /&gt;
=== Write barrier support. ===&lt;br /&gt;
&lt;br /&gt;
Write barrier support is enabled by default in XFS since kernel version 2.6.17. It is disabled by mounting the filesystem with &amp;quot;nobarrier&amp;quot;. Barrier support will flush the write back cache at the appropriate times (such as on XFS log writes). This is generally the recommended solution, however, you should check the system logs to ensure it was successful. Barriers will be disabled and reported in the log if any of the 3 scenarios occurs:&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;Disabling barriers, not supported with external log device&amp;quot;&lt;br /&gt;
* &amp;quot;Disabling barriers, not supported by the underlying device&amp;quot;&lt;br /&gt;
* &amp;quot;Disabling barriers, trial barrier write failed&amp;quot;&lt;br /&gt;
&lt;br /&gt;
If the filesystem is mounted with an external log device then we currently don&#039;t support flushing to the data and log devices (this may change in the future). If the driver tells the block layer that the device does not support write cache flushing with the write cache enabled then it will report that the device doesn&#039;t support it. And finally we will actually test out a barrier write on the superblock and test its error state afterwards, reporting if it fails.&lt;br /&gt;
&lt;br /&gt;
== Q. Should barriers be enabled with storage which has a persistent write cache? ==&lt;br /&gt;
&lt;br /&gt;
Many hardware RAID have a persistent write cache which preserves it across power failure, interface resets, system crashes, etc. Using write barriers in this instance is not recommended and will in fact lower performance. Therefore, it is recommended to turn off the barrier support and mount the filesystem with &amp;quot;nobarrier&amp;quot;, assuming your RAID controller is infallible and not resetting randomly like some common ones do.  But take care about the hard disk write cache, which should be off.&lt;br /&gt;
&lt;br /&gt;
== Q. Which settings does my RAID controller need ? ==&lt;br /&gt;
&lt;br /&gt;
It&#039;s hard to tell because there are so many controllers. Please consult your RAID controller documentation to determine how to change these settings, but we try to give an overview here:&lt;br /&gt;
&lt;br /&gt;
Real RAID controllers (not those found onboard of mainboards) normally have a battery or flash backed cache (or an [http://en.wikipedia.org/wiki/Electric_double-layer_capacitor ultracapacitor] + flash memory &amp;quot;[http://www.tweaktown.com/articles/2800/adaptec_zero_maintenance_cache_protection_explained/ zero maintenance cache]&amp;quot;) which is used for buffering writes to improve speed. This battery backed cache should ensure that if power fails or a PSU dies, the contents of the cache will be written to disk on next boot. However, the individual hard disk write caches need to be turned off, as they are not protected from a powerfail and will just lose all contents.&lt;br /&gt;
&lt;br /&gt;
If you do not have a battery or flash backed cache you should seriously consider disabling write cache if you value your data.&lt;br /&gt;
&lt;br /&gt;
* onboard RAID controllers: there are so many different types it&#039;s hard to tell. Generally, those controllers have no cache, but let the hard disk write cache on. That can lead to the bad situation that after a powerfail with RAID-1 when only parts of the disk cache have been written, the controller doesn&#039;t even see that the disks are out of sync, as the disks can resort cached blocks and might have saved the superblock info, but then lost different data contents. So, turn off disk write caches before using the RAID function.&lt;br /&gt;
&lt;br /&gt;
* 3ware: /cX/uX set cache=off, this will disable the controller and disk cache (see http://www.3ware.com/support/UserDocs/CLIGuide-9.5.1.1.pdf, page 86); &lt;br /&gt;
&lt;br /&gt;
* Adaptec: allows setting individual drives cache&lt;br /&gt;
arcconf setcache &amp;lt;disk&amp;gt; wb|wt&lt;br /&gt;
wb=write back, which means write cache on, wt=write through, which means write cache off. So &amp;quot;wt&amp;quot; should be chosen.&lt;br /&gt;
&lt;br /&gt;
* Areca: In archttp under &amp;quot;System Controls&amp;quot; -&amp;gt; &amp;quot;System Configuration&amp;quot; there&#039;s the option &amp;quot;Disk Write Cache Mode&amp;quot; (defaults &amp;quot;Auto&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Off&amp;quot;: disk write cache is turned off&lt;br /&gt;
&lt;br /&gt;
&amp;quot;On&amp;quot;: disk write cache is enabled, this is not safe for your data but fast&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Auto&amp;quot;: If you use a BBM (battery backup module, which you really should use if you care about your data), the controller automatically turns disk writes off, to protect your data. In case no BBM is attached, the controller switches to &amp;quot;On&amp;quot;, because neither controller cache nor disk cache is safe so you don&#039;t seem to care about your data and just want high speed (which you get then).&lt;br /&gt;
&lt;br /&gt;
That&#039;s a very sensible default so you can let it &amp;quot;Auto&amp;quot; or enforce &amp;quot;Off&amp;quot; to be sure.&lt;br /&gt;
&lt;br /&gt;
* LSI MegaRAID: allows setting individual disks cache:&lt;br /&gt;
 MegaCli -AdpCacheFlush -aN|-a0,1,2|-aALL                          # flushes the controller cache&lt;br /&gt;
 MegaCli -LDGetProp -Cache    -LN|-L0,1,2|-LAll -aN|-a0,1,2|-aALL  # shows the controller cache settings&lt;br /&gt;
 MegaCli -LDGetProp -DskCache -LN|-L0,1,2|-LAll -aN|-a0,1,2|-aALL  # shows the disk cache settings (for all phys. disks in logical disk)&lt;br /&gt;
 MegaCli -LDSetProp -EnDskCache|DisDskCache  -LN|-L0,1,2|-LAll  -aN|-a0,1,2|-aALL # set disk cache setting&lt;br /&gt;
&lt;br /&gt;
* Xyratex: from the docs: &amp;quot;Write cache includes the disk drive cache and controller cache.&amp;quot;. So that means you can only set the drive caches and the unit caches together. To protect your data, turn it off, but write performance will suffer badly as also the controller write cache is disabled.&lt;br /&gt;
&lt;br /&gt;
== Q: Which settings are best with virtualization like VMware, XEN, qemu? ==&lt;br /&gt;
&lt;br /&gt;
The biggest problem is that those products seem to also virtualize disk &lt;br /&gt;
writes in a way that even barriers don&#039;t work any more, which means even &lt;br /&gt;
a fsync is not reliable. Tests confirm that unplugging the power from &lt;br /&gt;
such a system even with RAID controller with battery backed cache and &lt;br /&gt;
hard disk cache turned off (which is safe on a normal host) you can &lt;br /&gt;
destroy a database within the virtual machine (client, domU whatever you &lt;br /&gt;
call it).&lt;br /&gt;
&lt;br /&gt;
In qemu you can specify cache=off on the line specifying the virtual &lt;br /&gt;
disk. For others information is missing.&lt;br /&gt;
&lt;br /&gt;
== Q: What is the issue with directory corruption in Linux 2.6.17? ==&lt;br /&gt;
&lt;br /&gt;
In the Linux kernel 2.6.17 release a subtle bug was accidentally introduced into the XFS directory code by some &amp;quot;sparse&amp;quot; endian annotations. This bug was sufficiently uncommon (it only affects a certain type of format change, in Node or B-Tree format directories, and only in certain situations) that it was not detected during our regular regression testing, but it has been observed in the wild by a number of people now.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Update: the fix is included in 2.6.17.7 and later kernels.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
To add insult to injury, &#039;&#039;&#039;xfs_repair(8)&#039;&#039;&#039; is currently not correcting these directories on detection of this corrupt state either. This &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; issue is actively being worked on, and a fixed version will be available shortly.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Update: a fixed &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; is now available; version 2.8.10 or later of the xfsprogs package contains the fixed version.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
No other kernel versions are affected. However, using a corrupt filesystem on other kernels can still result in the filesystem being shutdown if the problem has not been rectified (on disk), making it seem like other kernels are affected.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;xfs_check&#039;&#039;&#039; tool, or &#039;&#039;&#039;xfs_repair -n&#039;&#039;&#039;, should be able to detect any directory corruption.&lt;br /&gt;
&lt;br /&gt;
Until a fixed &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; binary is available, one can make use of the &#039;&#039;&#039;xfs_db(8)&#039;&#039;&#039; command to mark the problem directory for removal (see the example below). A subsequent &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; invocation will remove the directory and move all contents into &amp;quot;lost+found&amp;quot;, named by inode number (see second example on how to map inode number to directory entry name, which needs to be done _before_ removing the directory itself). The inode number of the corrupt directory is included in the shutdown report issued by the kernel on detection of directory corruption. Using that inode number, this is how one would ensure it is removed:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 # xfs_db -x /dev/sdXXX&lt;br /&gt;
 xfs_db&amp;amp;gt; inode NNN&lt;br /&gt;
 xfs_db&amp;amp;gt; print&lt;br /&gt;
 core.magic = 0x494e&lt;br /&gt;
 core.mode = 040755&lt;br /&gt;
 core.version = 2&lt;br /&gt;
 core.format = 3 (btree)&lt;br /&gt;
 ...&lt;br /&gt;
 xfs_db&amp;amp;gt; write core.mode 0&lt;br /&gt;
 xfs_db&amp;amp;gt; quit&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A subsequent &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; will clear the directory, and add new entries (named by inode number) in lost+found.&lt;br /&gt;
&lt;br /&gt;
The easiest way to map inode numbers to full paths is via &#039;&#039;&#039;xfs_ncheck(8)&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;: &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 # xfs_ncheck -i 14101 -i 14102 /dev/sdXXX&lt;br /&gt;
       14101 full/path/mumble_fratz_foo_bar_1495&lt;br /&gt;
       14102 full/path/mumble_fratz_foo_bar_1494&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Should this not work, we can manually map inode numbers in B-Tree format directory by taking the following steps:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 # xfs_db -x /dev/sdXXX&lt;br /&gt;
 xfs_db&amp;amp;gt; inode NNN&lt;br /&gt;
 xfs_db&amp;amp;gt; print&lt;br /&gt;
 core.magic = 0x494e&lt;br /&gt;
 ...&lt;br /&gt;
 next_unlinked = null&lt;br /&gt;
 u.bmbt.level = 1&lt;br /&gt;
 u.bmbt.numrecs = 1&lt;br /&gt;
 u.bmbt.keys[1] = [startoff] 1:[0]&lt;br /&gt;
 u.bmbt.ptrs[1] = 1:3628&lt;br /&gt;
 xfs_db&amp;amp;gt; fsblock 3628&lt;br /&gt;
 xfs_db&amp;amp;gt; type bmapbtd&lt;br /&gt;
 xfs_db&amp;amp;gt; print&lt;br /&gt;
 magic = 0x424d4150&lt;br /&gt;
 level = 0&lt;br /&gt;
 numrecs = 19&lt;br /&gt;
 leftsib = null&lt;br /&gt;
 rightsib = null&lt;br /&gt;
 recs[1-19] = [startoff,startblock,blockcount,extentflag]&lt;br /&gt;
        1:[0,3088,4,0] 2:[4,3128,8,0] 3:[12,3308,4,0] 4:[16,3360,4,0]&lt;br /&gt;
        5:[20,3496,8,0] 6:[28,3552,8,0] 7:[36,3624,4,0] 8:[40,3633,4,0]&lt;br /&gt;
        9:[44,3688,8,0] 10:[52,3744,4,0] 11:[56,3784,8,0]&lt;br /&gt;
        12:[64,3840,8,0] 13:[72,3896,4,0] 14:[33554432,3092,4,0]&lt;br /&gt;
        15:[33554436,3488,8,0] 16:[33554444,3629,4,0]&lt;br /&gt;
        17:[33554448,3748,4,0] 18:[33554452,3900,4,0]&lt;br /&gt;
        19:[67108864,3364,4,0]&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At this point we are looking at the extents that hold all of the directory information. There are three types of extent here, we have the data blocks (extents 1 through 13 above), then the leaf blocks (extents 14 through 18), then the freelist blocks (extent 19 above). The jumps in the first field (start offset) indicate our progression through each of the three types. For recovering file names, we are only interested in the data blocks, so we can now feed those offset numbers into the &#039;&#039;&#039;xfs_db&#039;&#039;&#039; dblock command. So, for the fifth extent - 5:[20,3496,8,0] - listed above:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
 xfs_db&amp;amp;gt; dblock 20&lt;br /&gt;
 xfs_db&amp;amp;gt; print&lt;br /&gt;
 dhdr.magic = 0x58443244&lt;br /&gt;
 dhdr.bestfree[0].offset = 0&lt;br /&gt;
 dhdr.bestfree[0].length = 0&lt;br /&gt;
 dhdr.bestfree[1].offset = 0&lt;br /&gt;
 dhdr.bestfree[1].length = 0&lt;br /&gt;
 dhdr.bestfree[2].offset = 0&lt;br /&gt;
 dhdr.bestfree[2].length = 0&lt;br /&gt;
 du[0].inumber = 13937&lt;br /&gt;
 du[0].namelen = 25&lt;br /&gt;
 du[0].name = &amp;quot;mumble_fratz_foo_bar_1595&amp;quot;&lt;br /&gt;
 du[0].tag = 0x10&lt;br /&gt;
 du[1].inumber = 13938&lt;br /&gt;
 du[1].namelen = 25&lt;br /&gt;
 du[1].name = &amp;quot;mumble_fratz_foo_bar_1594&amp;quot;&lt;br /&gt;
 du[1].tag = 0x38&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
So, here we can see that inode number 13938 matches up with name &amp;quot;mumble_fratz_foo_bar_1594&amp;quot;. Iterate through all the extents, and extract all the name-to-inode-number mappings you can, as these will be useful when looking at &amp;quot;lost+found&amp;quot; (once &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; has removed the corrupt directory).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Q: Why does my &amp;gt; 2TB XFS partition disappear when I reboot ? ==&lt;br /&gt;
&lt;br /&gt;
Strictly speaking this is not an XFS problem.&lt;br /&gt;
&lt;br /&gt;
To support &amp;gt; 2TB partitions you need two things: a kernel that supports large block devices (&amp;lt;tt&amp;gt;CONFIG_LBD=y&amp;lt;/tt&amp;gt;) and a partition table format that can hold large partitions.  The default DOS partition tables don&#039;t.  The best partition format for&lt;br /&gt;
&amp;gt; 2TB partitions is the EFI GPT format (&amp;lt;tt&amp;gt;CONFIG_EFI_PARTITION=y&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Without CONFIG_LBD=y you can&#039;t even create the filesystem, but without &amp;lt;tt&amp;gt;CONFIG_EFI_PARTITION=y&amp;lt;/tt&amp;gt; it works fine until you reboot at which point the partition will disappear.  Note that you need to enable the &amp;lt;tt&amp;gt;CONFIG_PARTITION_ADVANCED&amp;lt;/tt&amp;gt; option before you can set &amp;lt;tt&amp;gt;CONFIG_EFI_PARTITION=y&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Q: Why do I receive &amp;lt;tt&amp;gt;No space left on device&amp;lt;/tt&amp;gt; after &amp;lt;tt&amp;gt;xfs_growfs&amp;lt;/tt&amp;gt;? ==&lt;br /&gt;
&lt;br /&gt;
After [http://oss.sgi.com/pipermail/xfs/2009-January/039828.html growing a XFS filesystem], df(1) would show enough free space but attempts to write to the filesystem result in -ENOSPC. To fix this, [http://oss.sgi.com/pipermail/xfs/2009-January/039835.html Dave Chinner advised]:&lt;br /&gt;
&lt;br /&gt;
  The only way to fix this is to move data around to free up space&lt;br /&gt;
  below 1TB. Find your oldest data (i.e. that was around before even&lt;br /&gt;
  the first grow) and move it off the filesystem (move, not copy).&lt;br /&gt;
  Then if you copy it back on, the data blocks will end up above 1TB&lt;br /&gt;
  and that should leave you with plenty of space for inodes below 1TB.&lt;br /&gt;
  &lt;br /&gt;
  A complete dump and restore will also fix the problem ;)&lt;br /&gt;
&lt;br /&gt;
Also, you can add &#039;inode64&#039; to your mount options to allow inodes to live above 1TB.&lt;br /&gt;
&lt;br /&gt;
example:[https://www.centos.org/modules/newbb/viewtopic.php?topic_id=30703&amp;amp;forum=38 | No space left on device on xfs filesystem with 7.7TB free]&lt;br /&gt;
&lt;br /&gt;
== Q: Is using noatime or/and nodiratime at mount time giving any performance benefits in xfs (or not using them performance decrease)? ==&lt;br /&gt;
&lt;br /&gt;
The default atime behaviour is relatime, which has almost no overhead compared to noatime but still maintains sane atime values. All Linux filesystems use this as the default now (since around 2.6.30), but XFS has used relatime-like behaviour since 2006, so no-one should really need to ever use noatime on XFS for performance reasons. &lt;br /&gt;
&lt;br /&gt;
Also, noatime implies nodiratime, so there is never a need to specify nodiratime when noatime is also specified.&lt;br /&gt;
&lt;br /&gt;
== Q: How to get around a bad inode repair is unable to clean up ==&lt;br /&gt;
&lt;br /&gt;
The trick is go in with xfs_db and mark the inode as a deleted, which will cause repair to clean it up and finish the remove process.&lt;br /&gt;
&lt;br /&gt;
  xfs_db -x -c &#039;inode XXX&#039; -c &#039;write core.nextents 0&#039; -c &#039;write core.size 0&#039; /dev/hdXX&lt;br /&gt;
&lt;br /&gt;
== Q: How to calculate the correct sunit,swidth values for optimal performance ==&lt;br /&gt;
&lt;br /&gt;
XFS allows to optimize for a given RAID stripe unit (stripe size) and stripe width (number of data disks) via mount options.&lt;br /&gt;
&lt;br /&gt;
These options can be sometimes autodetected (for example with md raid and recent enough kernel (&amp;gt;= 2.6.32) and xfsprogs (&amp;gt;= 3.1.1) built with libblkid support) but manual calculation is needed for most of hardware raids.&lt;br /&gt;
&lt;br /&gt;
The calculation of these values is quite simple:&lt;br /&gt;
&lt;br /&gt;
  su = &amp;lt;RAID controllers stripe size in BYTES (or KiBytes when used with k)&amp;gt;&lt;br /&gt;
  sw = &amp;lt;# of data disks (don&#039;t count parity disks)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So if your RAID controller has a stripe size of 64KB, and you have a RAID-6 with 8 disks, use&lt;br /&gt;
&lt;br /&gt;
  su = 64k&lt;br /&gt;
  sw = 6 (RAID-6 of 8 disks has 6 data disks)&lt;br /&gt;
&lt;br /&gt;
A RAID stripe size of 256KB with a RAID-10 over 16 disks should use&lt;br /&gt;
&lt;br /&gt;
  su = 256k&lt;br /&gt;
  sw = 8 (RAID-10 of 16 disks has 8 data disks)&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can use &amp;quot;sunit&amp;quot; instead of &amp;quot;su&amp;quot; and &amp;quot;swidth&amp;quot; instead of &amp;quot;sw&amp;quot; but then sunit/swidth values need to be specified in &amp;quot;number of 512B sectors&amp;quot;!&lt;br /&gt;
&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;xfs_info&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;mkfs.xfs&amp;lt;/tt&amp;gt; interpret sunit and swidth as being specified in units of 512B sectors; that&#039;s unfortunately not the unit they&#039;re reported in, however.&lt;br /&gt;
&amp;lt;tt&amp;gt;xfs_info&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;mkfs.xfs&amp;lt;/tt&amp;gt; report them in multiples of your basic block size (bsize) and not in 512B sectors.&lt;br /&gt;
&lt;br /&gt;
Assume for example: swidth 1024 (specified at mkfs.xfs command line; so 1024 of 512B sectors) and block size of 4096 (bsize reported by mkfs.xfs at output). You should see swidth 128 (reported by mkfs.xfs at output). 128 * 4096 == 1024 * 512.&lt;br /&gt;
&lt;br /&gt;
When creating XFS filesystem on top of LVM on top of hardware raid please use sunit/swith values as when creating XFS filesystem directly on top of hardware raid.&lt;br /&gt;
&lt;br /&gt;
== Q: Why doesn&#039;t NFS-exporting subdirectories of inode64-mounted filesystem work? ==&lt;br /&gt;
&lt;br /&gt;
The default &amp;lt;tt&amp;gt;fsid&amp;lt;/tt&amp;gt; type encodes only 32-bit of the inode number for subdirectory exports.  However, exporting the root of the filesystem works, or using one of the non-default &amp;lt;tt&amp;gt;fsid&amp;lt;/tt&amp;gt; types (&amp;lt;tt&amp;gt;fsid=uuid&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;/etc/exports&amp;lt;/tt&amp;gt; with recent &amp;lt;tt&amp;gt;nfs-utils&amp;lt;/tt&amp;gt;) should work as well. (Thanks, Christoph!)&lt;br /&gt;
&lt;br /&gt;
== Q: What is the inode64 mount option for? ==&lt;br /&gt;
&lt;br /&gt;
By default, with 32bit inodes, XFS places inodes only in the first 1TB of a disk. If you have a disk with 100TB, all inodes will be stuck in the first TB. This can lead to strange things like &amp;quot;disk full&amp;quot; when you still have plenty space free, but there&#039;s no more place in the first TB to create a new inode. Also, performance sucks.&lt;br /&gt;
&lt;br /&gt;
To come around this, use the inode64 mount options for filesystems &amp;gt;1TB. Inodes will then be placed in the location where their data is, minimizing disk seeks.&lt;br /&gt;
&lt;br /&gt;
Beware that some old programs might have problems reading 64bit inodes, especially over NFS. Your editor used inode64 for over a year with recent (openSUSE 11.1 and higher) distributions using NFS and Samba without any corruptions, so that might be a recent enough distro.&lt;br /&gt;
&lt;br /&gt;
== Q: Can I just try the inode64 option to see if it helps me? ==&lt;br /&gt;
&lt;br /&gt;
Starting from kernel 2.6.35, you can try and then switch back. Older kernels have a bug leading to strange problems if you mount without inode64 again. For example, you can&#039;t access files &amp;amp; dirs that have been created with an inode &amp;gt;32bit anymore.&lt;br /&gt;
&lt;br /&gt;
== Q: Performance: mkfs.xfs -n size=64k option ==&lt;br /&gt;
&lt;br /&gt;
Asking the implications of that mkfs option on the XFS mailing list, Dave Chinner explained it this way:&lt;br /&gt;
&lt;br /&gt;
Inodes are not stored in the directory structure, only the directory entry name and the inode number. Hence the amount of space used by a&lt;br /&gt;
directory entry is determined by the length of the name.&lt;br /&gt;
&lt;br /&gt;
There is extra overhead to allocate large directory blocks (16 pages instead of one, to begin with, then there&#039;s the vmap overhead, etc), so for small directories smaller block sizes are faster for create and unlink operations.&lt;br /&gt;
&lt;br /&gt;
For empty directories, operations on 4k block sized directories consume roughly 50% less CPU that 64k block size directories. The 4k block size directories consume less CPU out to roughly 1.5 million entries where the two are roughly equal. At directory sizes of 10 million entries, 64k directory block operations are consuming about 15% of the CPU that 4k directory block operations consume.&lt;br /&gt;
&lt;br /&gt;
In terms of lookups, the 64k block directory will take less IO but consume more CPU for a given lookup. Hence it depends on your IO latency and whether directory readahead can hide that latency as to which will be faster. e.g. For SSDs, CPU usage might be the limiting factor, not the IO. Right now I don&#039;t have any numbers on what the difference might be - I&#039;m getting 1 billion inode population issues worked out first before I start on measuring cold cache lookup times on 1 billion files....&lt;br /&gt;
&lt;br /&gt;
== Q: I want to tune my XFS filesystems for &amp;lt;something&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
The standard answer you will get to this question is this: use the defaults.&lt;br /&gt;
&lt;br /&gt;
There are few workloads where using non-default mkfs.xfs or mount options make much sense. In general, the default values already used are optimised for best performance in the first place. mkfs.xfs will detect the difference between single disk and MD/DM RAID setups and change the default values it uses to  configure the filesystem appropriately.&lt;br /&gt;
&lt;br /&gt;
There are a lot of &amp;quot;XFS tuning guides&amp;quot; that Google will find for you - most are old, out of date and full of misleading or just plain incorrect information. Don&#039;t expect that tuning your filesystem for optimal bonnie++ numbers will mean your workload will go faster. You should only consider changing the defaults if either: a) you know from experience that your workload causes XFS a specific problem that can be worked around via a configuration change, or b) your workload is demonstrating bad performance when using the default configurations. In this case, you need to understand why your application is causing bad performance before you start tweaking XFS configurations.&lt;br /&gt;
&lt;br /&gt;
In most cases, the only thing you need to to consider for &amp;lt;tt&amp;gt;mkfs.xfs&amp;lt;/tt&amp;gt; is specifying the stripe unit and width for hardware RAID devices. For mount options, the only thing that will change metadata performance considerably are the &amp;lt;tt&amp;gt;logbsize&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;delaylog&amp;lt;/tt&amp;gt; mount options. Increasing &amp;lt;tt&amp;gt;logbsize&amp;lt;/tt&amp;gt; reduces the number of journal IOs for a given workload, and &amp;lt;tt&amp;gt;delaylog&amp;lt;/tt&amp;gt; will reduce them even further. The trade off for this increase in metadata performance is that more operations may be &amp;quot;missing&amp;quot; after recovery if the system crashes while actively making modifications.&lt;br /&gt;
&lt;br /&gt;
As of kernel 3.2.12, the default i/o scheduler, CFQ, will defeat much of the parallelization in XFS.&lt;br /&gt;
&lt;br /&gt;
== Q: Which factors influence the memory usage of xfs_repair? ==&lt;br /&gt;
&lt;br /&gt;
This is best explained with an example. The example filesystem is 16Tb, but basically empty (look at icount).&lt;br /&gt;
&lt;br /&gt;
  # xfs_repair -n -vv -m 1 /dev/vda&lt;br /&gt;
  Phase 1 - find and verify superblock...&lt;br /&gt;
          - max_mem = 1024, icount = 64, imem = 0, dblock = 4294967296, dmem = 2097152&lt;br /&gt;
  Required memory for repair is greater that the maximum specified&lt;br /&gt;
  with the -m option. Please increase it to at least 2096.&lt;br /&gt;
  #&lt;br /&gt;
&lt;br /&gt;
xfs_repair is saying it needs at least 2096MB of RAM to repair the filesystem,&lt;br /&gt;
of which 2,097,152KB is needed for tracking free space. &lt;br /&gt;
(The -m 1 argument was telling xfs_repair to use ony 1 MB of memory.)&lt;br /&gt;
&lt;br /&gt;
Now if we add some inodes (50 million) to the filesystem (look at icount again), and the result is:&lt;br /&gt;
&lt;br /&gt;
  # xfs_repair -vv -m 1 /dev/vda&lt;br /&gt;
  Phase 1 - find and verify superblock...&lt;br /&gt;
          - max_mem = 1024, icount = 50401792, imem = 196882, dblock = 4294967296, dmem = 2097152&lt;br /&gt;
  Required memory for repair is greater that the maximum specified&lt;br /&gt;
  with the -m option. Please increase it to at least 2289.&lt;br /&gt;
&lt;br /&gt;
That is now needs at least another 200MB of RAM to run.&lt;br /&gt;
&lt;br /&gt;
The numbers reported by xfs_repair are the absolute minimum required and approximate at that;&lt;br /&gt;
more RAM than this may be required to complete successfully.&lt;br /&gt;
Also, if you only give xfs_repair the minimum required RAM, it will be slow;&lt;br /&gt;
for best repair performance, the more RAM you can give it the better.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Q: Why some files of my filesystem shows as &amp;quot;?????????? ? ?      ?          ?                ? filename&amp;quot; ? ==&lt;br /&gt;
&lt;br /&gt;
If ls -l shows you a listing as&lt;br /&gt;
&lt;br /&gt;
  # ?????????? ? ?      ?          ?                ? file1&lt;br /&gt;
    ?????????? ? ?      ?          ?                ? file2&lt;br /&gt;
    ?????????? ? ?      ?          ?                ? file3&lt;br /&gt;
    ?????????? ? ?      ?          ?                ? file4&lt;br /&gt;
&lt;br /&gt;
and errors like:&lt;br /&gt;
  # ls /pathtodir/&lt;br /&gt;
    ls: cannot access /pathtodir/file1: Invalid argument&lt;br /&gt;
    ls: cannot access /pathtodir/file2: Invalid argument&lt;br /&gt;
    ls: cannot access /pathtodir/file3: Invalid argument&lt;br /&gt;
    ls: cannot access /pathtodir/file4: Invalid argument&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
or even:&lt;br /&gt;
  # failed to stat /pathtodir/file1&lt;br /&gt;
&lt;br /&gt;
It is very probable your filesystem must be mounted with inode64&lt;br /&gt;
  # mount -oremount,inode64 /dev/diskpart /mnt/xfs&lt;br /&gt;
&lt;br /&gt;
should make it work ok again.&lt;br /&gt;
If it works, add the option to fstab.&lt;br /&gt;
&lt;br /&gt;
== Q: The xfs_db &amp;quot;frag&amp;quot; command says I&#039;m over 50%.  Is that bad? ==&lt;br /&gt;
&lt;br /&gt;
It depends.  It&#039;s important to know how the value is calculated.  xfs_db looks at the extents in all files, and returns:&lt;br /&gt;
&lt;br /&gt;
  (actual extents - ideal extents) / actual extents&lt;br /&gt;
&lt;br /&gt;
This means that if, for example, you have an average of 2 extents per file, you&#039;ll get an answer of 50%.  4 extents per file would give you 75%.  This may or may not be a problem, especially depending on the size of the files in question.  (i.e. 400GB files in four 100GB extents would hardly be considered badly fragmented).  The xfs_bmap command can be useful for displaying the actual fragmentation/layout of individual files.&lt;br /&gt;
&lt;br /&gt;
Note that above a few average extents per file, the fragmentation factor rapidly approaches 100%:&lt;br /&gt;
[[Image:Frag_factor.png|500px]]&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=XFS_FAQ&amp;diff=2483</id>
		<title>XFS FAQ</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=XFS_FAQ&amp;diff=2483"/>
		<updated>2012-04-23T23:57:08Z</updated>

		<summary type="html">&lt;p&gt;Dgc: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Info from: [http://oss.sgi.com/projects/xfs/faq.html main XFS faq at SGI]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Many thanks to earlier maintainers of this document - Thomas Graichen and Seth Mos.&lt;br /&gt;
&lt;br /&gt;
== Q: Where can I find documentation about XFS? ==&lt;br /&gt;
&lt;br /&gt;
The SGI XFS project page http://oss.sgi.com/projects/xfs/ is the definitive reference. It contains pointers to whitepapers, books, articles, etc.&lt;br /&gt;
&lt;br /&gt;
You could also join the [[XFS_email_list_and_archives|XFS mailing list]] or the &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;#xfs&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039; IRC channel on &#039;&#039;irc.freenode.net&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Q: Where can I find documentation about ACLs? ==&lt;br /&gt;
&lt;br /&gt;
Andreas Gruenbacher maintains the Extended Attribute and POSIX ACL documentation for Linux at http://acl.bestbits.at/&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;acl(5)&#039;&#039;&#039; manual page is also quite extensive.&lt;br /&gt;
&lt;br /&gt;
== Q: Where can I find information about the internals of XFS? ==&lt;br /&gt;
&lt;br /&gt;
An [http://oss.sgi.com/projects/xfs/training/ SGI XFS Training course] aimed at developers, triage and support staff, and serious users has been in development. Parts of the course are clearly still incomplete, but there is enough content to be useful to a broad range of users.&lt;br /&gt;
&lt;br /&gt;
Barry Naujok has documented the [http://oss.sgi.com/projects/xfs/papers/xfs_filesystem_structure.pdf XFS ondisk format] which is a very useful reference.&lt;br /&gt;
&lt;br /&gt;
== Q: What partition type should I use for XFS on Linux? ==&lt;br /&gt;
&lt;br /&gt;
Linux native filesystem (83).&lt;br /&gt;
&lt;br /&gt;
== Q: What mount options does XFS have? ==&lt;br /&gt;
&lt;br /&gt;
There are a number of mount options influencing XFS filesystems - refer to the &#039;&#039;&#039;mount(8)&#039;&#039;&#039; manual page or the documentation in the kernel source tree itself ([http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/filesystems/xfs.txt;hb=HEAD Documentation/filesystems/xfs.txt])&lt;br /&gt;
&lt;br /&gt;
== Q: Is there any relation between the XFS utilities and the kernel version? ==&lt;br /&gt;
&lt;br /&gt;
No, there is no relation. Newer utilities tend to mainly have fixes and checks the previous versions might not have. New features are also added in a backward compatible way - if they are enabled via mkfs, an incapable (old) kernel will recognize that it does not understand the new feature, and refuse to mount the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Q: Does it run on platforms other than i386? ==&lt;br /&gt;
&lt;br /&gt;
XFS runs on all of the platforms that Linux supports. It is more tested on the more common platforms, especially the i386 family. Its also well tested on the IA64 platform since thats the platform SGI Linux products use.&lt;br /&gt;
&lt;br /&gt;
== Q: Quota: Do quotas work on XFS? ==&lt;br /&gt;
&lt;br /&gt;
Yes.&lt;br /&gt;
&lt;br /&gt;
To use quotas with XFS, you need to enable XFS quota support when you configure your kernel. You also need to specify quota support when mounting. You can get the Linux quota utilities at their sourceforge website [http://sourceforge.net/projects/linuxquota/  http://sourceforge.net/projects/linuxquota/] or use &#039;&#039;&#039;xfs_quota(8)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Q: Quota: What&#039;s project quota? ==&lt;br /&gt;
&lt;br /&gt;
The  project  quota  is a quota mechanism in XFS can be used to implement a form of directory tree quota, where a specified directory and all of the files and subdirectories below it (i.e. a tree) can be restricted to using a subset of the available space in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Q: Quota: Can group quota and project quota be used at the same time? ==&lt;br /&gt;
&lt;br /&gt;
No, project quota cannot be used with group quota at the same time. On the other hand user quota and project quota can be used simultaneously.&lt;br /&gt;
&lt;br /&gt;
== Q: Quota: Is umounting prjquota (project quota) enabled fs and mounting it again with grpquota (group quota) removing prjquota limits previously set from fs (and vice versa) ? ==&lt;br /&gt;
&lt;br /&gt;
To be answered.&lt;br /&gt;
&lt;br /&gt;
== Q: Are there any dump/restore tools for XFS? ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;xfsdump(8)&#039;&#039;&#039; and &#039;&#039;&#039;xfsrestore(8)&#039;&#039;&#039; are fully supported. The tape format is the same as on IRIX, so tapes are interchangeable between operating systems.&lt;br /&gt;
&lt;br /&gt;
== Q: Does LILO work with XFS? ==&lt;br /&gt;
&lt;br /&gt;
This depends on where you install LILO.&lt;br /&gt;
&lt;br /&gt;
Yes, for MBR (Master Boot Record) installations.&lt;br /&gt;
&lt;br /&gt;
No, for root partition installations because the XFS superblock is written at block zero, where LILO would be installed. This is to maintain compatibility with the IRIX on-disk format, and will not be changed.&lt;br /&gt;
&lt;br /&gt;
== Q: Does GRUB work with XFS? ==&lt;br /&gt;
&lt;br /&gt;
There is native XFS filesystem support for GRUB starting with version 0.91 and onward. Unfortunately, GRUB used to make incorrect assumptions about being able to read a block device image while a filesystem is mounted and actively being written to, which could cause intermittent problems when using XFS. This has reportedly since been fixed, and the 0.97 version (at least) of GRUB is apparently stable.&lt;br /&gt;
&lt;br /&gt;
== Q: Can XFS be used for a root filesystem? ==&lt;br /&gt;
&lt;br /&gt;
Yes, with one caveat: Linux does not support an external XFS journal for the root filesystem via the &amp;quot;rootflags=&amp;quot; kernel parameter. To use an external journal for the root filesystem in Linux, an init ramdisk must mount the root filesystem with explicit &amp;quot;logdev=&amp;quot; specified. [http://mindplusplus.wordpress.com/2008/07/27/scratching-an-i.html More information here.]&lt;br /&gt;
&lt;br /&gt;
== Q: Will I be able to use my IRIX XFS filesystems on Linux? ==&lt;br /&gt;
&lt;br /&gt;
Yes. The on-disk format of XFS is the same on IRIX and Linux. Obviously, you should back-up your data before trying to move it between systems. Filesystems must be &amp;quot;clean&amp;quot; when moved (i.e. unmounted). If you plan to use IRIX filesystems on Linux keep the following points in mind: the kernel needs to have SGI partition support enabled; there is no XLV support in Linux, so you are unable to read IRIX filesystems which use the XLV volume manager; also not all blocksizes available on IRIX are available on Linux (only blocksizes less than or equal to the pagesize of the architecture: 4k for i386, ppc, ... 8k for alpha, sparc, ... is possible for now). Make sure that the directory format is version 2 on the IRIX filesystems (this is the default since IRIX 6.5.5). Linux can only read v2 directories.&lt;br /&gt;
&lt;br /&gt;
== Q: Is there a way to make a XFS filesystem larger or smaller? ==&lt;br /&gt;
&lt;br /&gt;
You can &#039;&#039;NOT&#039;&#039; make a XFS partition smaller online. The only way to shrink is to do a complete dump, mkfs and restore.&lt;br /&gt;
&lt;br /&gt;
An XFS filesystem may be enlarged by using &#039;&#039;&#039;xfs_growfs(8)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
If using partitions, you need to have free space after this partition to do so. Remove partition, recreate it larger with the &#039;&#039;exact same&#039;&#039; starting point. Run &#039;&#039;&#039;xfs_growfs&#039;&#039;&#039; to make the partition larger. Note - editing partition tables is a dangerous pastime, so back up your filesystem before doing so.&lt;br /&gt;
&lt;br /&gt;
Using XFS filesystems on top of a volume manager makes this a lot easier.&lt;br /&gt;
&lt;br /&gt;
== Q: What information should I include when reporting a problem? ==&lt;br /&gt;
&lt;br /&gt;
What you need to report depend on the problem you are seeing. Firstly, your machine hardware and storage configuration needs to be described. That includes:&lt;br /&gt;
&lt;br /&gt;
* kernel version (uname -a)&lt;br /&gt;
* xfsprogs version (xfs_repair -V)&lt;br /&gt;
* number of CPUs&lt;br /&gt;
* contents of /proc/meminfo&lt;br /&gt;
* contents of /proc/mounts&lt;br /&gt;
* contents of /proc/partitions&lt;br /&gt;
* RAID layout (hardware and/or software)&lt;br /&gt;
* LVM configuration&lt;br /&gt;
* type of disks you are using&lt;br /&gt;
* write cache status of drives&lt;br /&gt;
* size of BBWC and mode it is running in&lt;br /&gt;
* xfs_info output on the filesystem in question&lt;br /&gt;
* dmesg output showing all error messages and stack traces&lt;br /&gt;
 &lt;br /&gt;
Then you need to describe your workload that is causing the problem, and a demonstration of the bad behaviour that is occurring. If it is a performance problem, then 30s - 1 minute samples of:&lt;br /&gt;
&lt;br /&gt;
# iostat -x -d -m 5&lt;br /&gt;
# vmstat 5&lt;br /&gt;
 &lt;br /&gt;
can give us insight into the IO and memory utilisation of your machine at the time of the problem.&lt;br /&gt;
&lt;br /&gt;
If the filesystem is hanging, then capture the output of the dmesg command after running:&lt;br /&gt;
&lt;br /&gt;
 # echo w &amp;gt; /proc/sysrq-trigger&lt;br /&gt;
 # dmesg&lt;br /&gt;
&lt;br /&gt;
will tell us all the hung processes in the machine, often pointing us directly to the cause of the hang.&lt;br /&gt;
&lt;br /&gt;
And for advanced users, capturing an event trace using &#039;&#039;&#039;trace-cmd&#039;&#039;&#039; (git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/trace-cmd.git) will be very helpful. In many cases the XFS developers will ask for this information anyway, so it&#039;s a good idea to be ready with it in advance. Start the trace with this command:&lt;br /&gt;
&lt;br /&gt;
 # trace-cmd record -e xfs\*&lt;br /&gt;
&lt;br /&gt;
before the problem occurs, and once it has occurred, kill the trace-cmd with ctrl-C, and then run:&lt;br /&gt;
&lt;br /&gt;
 # trace-cmd report &amp;gt; trace_report.txt&lt;br /&gt;
&lt;br /&gt;
Compress the trace_report.txt file and include that with the bug report.&lt;br /&gt;
&lt;br /&gt;
If you have a problem with &#039;&#039;&#039;xfs_repair(8)&#039;&#039;&#039;, make sure that you save the entire output of the problematic run so that the developers can see exactly where it encountered the problem. You might be asked to capture the metadata in the filesystem using &#039;&#039;&#039;xfs_metadump(8)&#039;&#039;&#039; (which obfuscates filenames and attributes to protect your privacy) and make the dump available for someone to analyse.&lt;br /&gt;
&lt;br /&gt;
== Q: Mounting an XFS filesystem does not work - what is wrong? ==&lt;br /&gt;
&lt;br /&gt;
If mount prints an error message something like:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
     mount: /dev/hda5 has wrong major or minor number&lt;br /&gt;
&lt;br /&gt;
you either do not have XFS compiled into the kernel (or you forgot to load the modules) or you did not use the &amp;quot;-t xfs&amp;quot; option on mount or the &amp;quot;xfs&amp;quot; option in &amp;lt;tt&amp;gt;/etc/fstab&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you get something like:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 mount: wrong fs type, bad option, bad superblock on /dev/sda1,&lt;br /&gt;
        or too many mounted file systems&lt;br /&gt;
&lt;br /&gt;
Refer to your system log file (&amp;lt;tt&amp;gt;/var/log/messages&amp;lt;/tt&amp;gt;) for a detailed diagnostic message from the kernel.&lt;br /&gt;
&lt;br /&gt;
== Q: Does the filesystem have an undelete capability? ==&lt;br /&gt;
&lt;br /&gt;
There is no undelete in XFS (so far).&lt;br /&gt;
&lt;br /&gt;
However at least some XFS driver implementations do not wipe file information nodes completely so there are chance to recover files with specialized commercial closed source software like [http://www.ufsexplorer.com/rdr_xfs.php Raise Data Recovery for XFS].&lt;br /&gt;
&lt;br /&gt;
In this kind of XFS driver implementation it does not re-use directory entries immediately so there are chance to get back recently deleted files even with their real names.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;xfs_irecover&#039;&#039; or &#039;&#039;xfsr&#039;&#039; may help too, [http://www.who.is.free.fr/wiki/doku.php?id=recover this site] has a few links.&lt;br /&gt;
&lt;br /&gt;
This applies to most recent Linux distributions (versions?), as well as to most popular NAS boxes that use embedded linux and XFS file system.&lt;br /&gt;
&lt;br /&gt;
Anyway, the best is to always keep backups.&lt;br /&gt;
&lt;br /&gt;
== Q: How can I backup a XFS filesystem and ACLs? ==&lt;br /&gt;
&lt;br /&gt;
You can backup a XFS filesystem with utilities like &#039;&#039;&#039;xfsdump(8)&#039;&#039;&#039; and standard &#039;&#039;&#039;tar(1)&#039;&#039;&#039; for standard files. If you want to backup ACLs you will need to use &#039;&#039;&#039;xfsdump&#039;&#039;&#039; or [http://www.bacula.org/en/dev-manual/Current_State_Bacula.html Bacula] (&amp;gt; version 3.1.4) or [http://rsync.samba.org/ rsync] (&amp;gt;= version 3.0.0) to backup ACLs and EAs. &#039;&#039;&#039;xfsdump&#039;&#039;&#039; can also be integrated with [http://www.amanda.org/ amanda(8)].&lt;br /&gt;
&lt;br /&gt;
== Q: I see applications returning error 990 or &amp;quot;Structure needs cleaning&amp;quot;, what is wrong? ==&lt;br /&gt;
&lt;br /&gt;
The error 990 stands for [http://oss.sgi.com/cgi-bin/gitweb.cgi?p=xfs/xfs.git;a=blob;f=fs/xfs/linux-2.6/xfs_linux.h#l145 EFSCORRUPTED] which usually means XFS has detected a filesystem metadata problem and has shut the filesystem down to prevent further damage. Also, since about June 2006, we [http://oss.sgi.com/cgi-bin/gitweb.cgi?p=xfs/xfs.git;a=commit;h=da2f4d679c8070ba5b6a920281e495917b293aa0 converted from EFSCORRUPTED/990 over to using EUCLEAN], &amp;quot;Structure needs cleaning.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The cause can be pretty much anything, unfortunately - filesystem, virtual memory manager, volume manager, device driver, or hardware.&lt;br /&gt;
&lt;br /&gt;
There should be a detailed console message when this initially happens. The messages have important information giving hints to developers as to the earliest point that a problem was detected. It is there to protect your data.&lt;br /&gt;
&lt;br /&gt;
You can use xfs_check and xfs_repair to remedy the problem (with the file system unmounted).&lt;br /&gt;
&lt;br /&gt;
== Q: Why do I see binary NULLS in some files after recovery when I unplugged the power? ==&lt;br /&gt;
&lt;br /&gt;
Update: This issue has been addressed with a CVS fix on the 29th March 2007 and merged into mainline on 8th May 2007 for 2.6.22-rc1.&lt;br /&gt;
&lt;br /&gt;
XFS journals metadata updates, not data updates. After a crash you are supposed to get a consistent filesystem which looks like the state sometime shortly before the crash, NOT what the in memory image looked like the instant before the crash.&lt;br /&gt;
&lt;br /&gt;
Since XFS does not write data out immediately unless you tell it to with fsync, an O_SYNC or O_DIRECT open (the same is true of other filesystems), you are looking at an inode which was flushed out, but whose data was not. Typically you&#039;ll find that the inode is not taking any space since all it has is a size but no extents allocated (try examining the file with the &#039;&#039;&#039;xfs_bmap(8)&#039;&#039;&#039; command).&lt;br /&gt;
&lt;br /&gt;
== Q: What is the problem with the write cache on journaled filesystems? ==&lt;br /&gt;
&lt;br /&gt;
Many drives use a write back cache in order to speed up the performance of writes.  However, there are conditions such as power failure when the write cache memory is never flushed to the actual disk.  Further, the drive can de-stage data from the write cache to the platters in any order that it chooses.  This causes problems for XFS and journaled filesystems in general because they rely on knowing when a write has completed to the disk. They need to know that the log information has made it to disk before allowing metadata to go to disk.  When the metadata makes it to disk then the transaction can effectively be deleted from the log resulting in movement of the tail of the log and thus freeing up some log space. So if the writes never make it to the physical disk, then the ordering is violated and the log and metadata can be lost, resulting in filesystem corruption.&lt;br /&gt;
&lt;br /&gt;
With hard disk cache sizes of currently (Jan 2009) up to 32MB that can be a lot of valuable information.  In a RAID with 8 such disks these adds to 256MB, and the chance of having filesystem metadata in the cache is so high that you have a very high chance of big data losses on a power outage.&lt;br /&gt;
&lt;br /&gt;
With a single hard disk and barriers turned on (on=default), the drive write cache is flushed before and after a barrier is issued.  A powerfail &amp;quot;only&amp;quot; loses data in the cache but no essential ordering is violated, and corruption will not occur.&lt;br /&gt;
&lt;br /&gt;
With a RAID controller with battery backed controller cache and cache in write back mode, you should turn off barriers - they are unnecessary in this case, and if the controller honors the cache flushes, it will be harmful to performance.  But then you *must* disable the individual hard disk write cache in order to ensure to keep the filesystem intact after a power failure. The method for doing this is different for each RAID controller. See the section about RAID controllers below.&lt;br /&gt;
&lt;br /&gt;
== Q: How can I tell if I have the disk write cache enabled? ==&lt;br /&gt;
&lt;br /&gt;
For SCSI/SATA:&lt;br /&gt;
&lt;br /&gt;
* Look in dmesg(8) output for a driver line, such as:&amp;lt;br /&amp;gt; &amp;quot;SCSI device sda: drive cache: write back&amp;quot;&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;# sginfo -c /dev/sda | grep -i &#039;write cache&#039; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For PATA/SATA (although for SATA this only works on a recent kernel with ATA command passthrough):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;# hdparm -I /dev/sda&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; and look under &amp;quot;Enabled Supported&amp;quot; for &amp;quot;Write cache&amp;quot;&lt;br /&gt;
&lt;br /&gt;
For RAID controllers:&lt;br /&gt;
&lt;br /&gt;
* See the section about RAID controllers below&lt;br /&gt;
&lt;br /&gt;
== Q: How can I address the problem with the disk write cache? ==&lt;br /&gt;
&lt;br /&gt;
=== Disabling the disk write back cache. ===&lt;br /&gt;
&lt;br /&gt;
For SATA/PATA(IDE): (although for SATA this only works on a recent kernel with ATA command passthrough):&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;# hdparm -W0 /dev/sda&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; # hdparm -W0 /dev/hda&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;# blktool /dev/sda wcache off&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; # blktool /dev/hda wcache off&lt;br /&gt;
&lt;br /&gt;
For SCSI:&lt;br /&gt;
&lt;br /&gt;
* Using sginfo(8) which is a little tedious&amp;lt;br /&amp;gt; It takes 3 steps. For example:&lt;br /&gt;
*# &amp;lt;nowiki&amp;gt;#sginfo -c /dev/sda&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; which gives a list of attribute names and values&lt;br /&gt;
*# &amp;lt;nowiki&amp;gt;#sginfo -cX /dev/sda&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; which gives an array of cache values which you must match up with from step 1, e.g.&amp;lt;br /&amp;gt; 0 0 0 1 0 1 0 0 0 0 65535 0 65535 65535 1 0 0 0 3 0 0&lt;br /&gt;
*# &amp;lt;nowiki&amp;gt;#sginfo -cXR /dev/sda 0 0 0 1 0 0 0 0 0 0 65535 0 65535 65535 1 0 0 0 3 0 0&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; allows you to reset the value of the cache attributes.&lt;br /&gt;
&lt;br /&gt;
For RAID controllers:&lt;br /&gt;
&lt;br /&gt;
* See the section about RAID controllers below&lt;br /&gt;
&lt;br /&gt;
This disabling is kept persistent for a SCSI disk. However, for a SATA/PATA disk this needs to be done after every reset as it will reset back to the default of the write cache enabled. And a reset can happen after reboot or on error recovery of the drive. This makes it rather difficult to guarantee that the write cache is maintained as disabled.&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using an external log. ===&lt;br /&gt;
&lt;br /&gt;
Some people have considered the idea of using an external log on a separate drive with the write cache disabled and the rest of the file system on another disk with the write cache enabled. However, that will &#039;&#039;&#039;not&#039;&#039;&#039; solve the problem. For example, the tail of the log is moved when we are notified that a metadata write is completed to disk and we won&#039;t be able to guarantee that if the metadata is on a drive with the write cache enabled.&lt;br /&gt;
&lt;br /&gt;
In fact using an external log will disable XFS&#039; write barrier support.&lt;br /&gt;
&lt;br /&gt;
=== Write barrier support. ===&lt;br /&gt;
&lt;br /&gt;
Write barrier support is enabled by default in XFS since kernel version 2.6.17. It is disabled by mounting the filesystem with &amp;quot;nobarrier&amp;quot;. Barrier support will flush the write back cache at the appropriate times (such as on XFS log writes). This is generally the recommended solution, however, you should check the system logs to ensure it was successful. Barriers will be disabled and reported in the log if any of the 3 scenarios occurs:&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;Disabling barriers, not supported with external log device&amp;quot;&lt;br /&gt;
* &amp;quot;Disabling barriers, not supported by the underlying device&amp;quot;&lt;br /&gt;
* &amp;quot;Disabling barriers, trial barrier write failed&amp;quot;&lt;br /&gt;
&lt;br /&gt;
If the filesystem is mounted with an external log device then we currently don&#039;t support flushing to the data and log devices (this may change in the future). If the driver tells the block layer that the device does not support write cache flushing with the write cache enabled then it will report that the device doesn&#039;t support it. And finally we will actually test out a barrier write on the superblock and test its error state afterwards, reporting if it fails.&lt;br /&gt;
&lt;br /&gt;
== Q. Should barriers be enabled with storage which has a persistent write cache? ==&lt;br /&gt;
&lt;br /&gt;
Many hardware RAID have a persistent write cache which preserves it across power failure, interface resets, system crashes, etc. Using write barriers in this instance is not recommended and will in fact lower performance. Therefore, it is recommended to turn off the barrier support and mount the filesystem with &amp;quot;nobarrier&amp;quot;, assuming your RAID controller is infallible and not resetting randomly like some common ones do.  But take care about the hard disk write cache, which should be off.&lt;br /&gt;
&lt;br /&gt;
== Q. Which settings does my RAID controller need ? ==&lt;br /&gt;
&lt;br /&gt;
It&#039;s hard to tell because there are so many controllers. Please consult your RAID controller documentation to determine how to change these settings, but we try to give an overview here:&lt;br /&gt;
&lt;br /&gt;
Real RAID controllers (not those found onboard of mainboards) normally have a battery or flash backed cache (or an [http://en.wikipedia.org/wiki/Electric_double-layer_capacitor ultracapacitor] + flash memory &amp;quot;[http://www.tweaktown.com/articles/2800/adaptec_zero_maintenance_cache_protection_explained/ zero maintenance cache]&amp;quot;) which is used for buffering writes to improve speed. This battery backed cache should ensure that if power fails or a PSU dies, the contents of the cache will be written to disk on next boot. However, the individual hard disk write caches need to be turned off, as they are not protected from a powerfail and will just lose all contents.&lt;br /&gt;
&lt;br /&gt;
If you do not have a battery or flash backed cache you should seriously consider disabling write cache if you value your data.&lt;br /&gt;
&lt;br /&gt;
* onboard RAID controllers: there are so many different types it&#039;s hard to tell. Generally, those controllers have no cache, but let the hard disk write cache on. That can lead to the bad situation that after a powerfail with RAID-1 when only parts of the disk cache have been written, the controller doesn&#039;t even see that the disks are out of sync, as the disks can resort cached blocks and might have saved the superblock info, but then lost different data contents. So, turn off disk write caches before using the RAID function.&lt;br /&gt;
&lt;br /&gt;
* 3ware: /cX/uX set cache=off, this will disable the controller and disk cache (see http://www.3ware.com/support/UserDocs/CLIGuide-9.5.1.1.pdf, page 86); &lt;br /&gt;
&lt;br /&gt;
* Adaptec: allows setting individual drives cache&lt;br /&gt;
arcconf setcache &amp;lt;disk&amp;gt; wb|wt&lt;br /&gt;
wb=write back, which means write cache on, wt=write through, which means write cache off. So &amp;quot;wt&amp;quot; should be chosen.&lt;br /&gt;
&lt;br /&gt;
* Areca: In archttp under &amp;quot;System Controls&amp;quot; -&amp;gt; &amp;quot;System Configuration&amp;quot; there&#039;s the option &amp;quot;Disk Write Cache Mode&amp;quot; (defaults &amp;quot;Auto&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Off&amp;quot;: disk write cache is turned off&lt;br /&gt;
&lt;br /&gt;
&amp;quot;On&amp;quot;: disk write cache is enabled, this is not safe for your data but fast&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Auto&amp;quot;: If you use a BBM (battery backup module, which you really should use if you care about your data), the controller automatically turns disk writes off, to protect your data. In case no BBM is attached, the controller switches to &amp;quot;On&amp;quot;, because neither controller cache nor disk cache is safe so you don&#039;t seem to care about your data and just want high speed (which you get then).&lt;br /&gt;
&lt;br /&gt;
That&#039;s a very sensible default so you can let it &amp;quot;Auto&amp;quot; or enforce &amp;quot;Off&amp;quot; to be sure.&lt;br /&gt;
&lt;br /&gt;
* LSI MegaRAID: allows setting individual disks cache:&lt;br /&gt;
 MegaCli -AdpCacheFlush -aN|-a0,1,2|-aALL                          # flushes the controller cache&lt;br /&gt;
 MegaCli -LDGetProp -Cache    -LN|-L0,1,2|-LAll -aN|-a0,1,2|-aALL  # shows the controller cache settings&lt;br /&gt;
 MegaCli -LDGetProp -DskCache -LN|-L0,1,2|-LAll -aN|-a0,1,2|-aALL  # shows the disk cache settings (for all phys. disks in logical disk)&lt;br /&gt;
 MegaCli -LDSetProp -EnDskCache|DisDskCache  -LN|-L0,1,2|-LAll  -aN|-a0,1,2|-aALL # set disk cache setting&lt;br /&gt;
&lt;br /&gt;
* Xyratex: from the docs: &amp;quot;Write cache includes the disk drive cache and controller cache.&amp;quot;. So that means you can only set the drive caches and the unit caches together. To protect your data, turn it off, but write performance will suffer badly as also the controller write cache is disabled.&lt;br /&gt;
&lt;br /&gt;
== Q: Which settings are best with virtualization like VMware, XEN, qemu? ==&lt;br /&gt;
&lt;br /&gt;
The biggest problem is that those products seem to also virtualize disk &lt;br /&gt;
writes in a way that even barriers don&#039;t work any more, which means even &lt;br /&gt;
a fsync is not reliable. Tests confirm that unplugging the power from &lt;br /&gt;
such a system even with RAID controller with battery backed cache and &lt;br /&gt;
hard disk cache turned off (which is safe on a normal host) you can &lt;br /&gt;
destroy a database within the virtual machine (client, domU whatever you &lt;br /&gt;
call it).&lt;br /&gt;
&lt;br /&gt;
In qemu you can specify cache=off on the line specifying the virtual &lt;br /&gt;
disk. For others information is missing.&lt;br /&gt;
&lt;br /&gt;
== Q: What is the issue with directory corruption in Linux 2.6.17? ==&lt;br /&gt;
&lt;br /&gt;
In the Linux kernel 2.6.17 release a subtle bug was accidentally introduced into the XFS directory code by some &amp;quot;sparse&amp;quot; endian annotations. This bug was sufficiently uncommon (it only affects a certain type of format change, in Node or B-Tree format directories, and only in certain situations) that it was not detected during our regular regression testing, but it has been observed in the wild by a number of people now.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Update: the fix is included in 2.6.17.7 and later kernels.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
To add insult to injury, &#039;&#039;&#039;xfs_repair(8)&#039;&#039;&#039; is currently not correcting these directories on detection of this corrupt state either. This &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; issue is actively being worked on, and a fixed version will be available shortly.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Update: a fixed &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; is now available; version 2.8.10 or later of the xfsprogs package contains the fixed version.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
No other kernel versions are affected. However, using a corrupt filesystem on other kernels can still result in the filesystem being shutdown if the problem has not been rectified (on disk), making it seem like other kernels are affected.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;xfs_check&#039;&#039;&#039; tool, or &#039;&#039;&#039;xfs_repair -n&#039;&#039;&#039;, should be able to detect any directory corruption.&lt;br /&gt;
&lt;br /&gt;
Until a fixed &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; binary is available, one can make use of the &#039;&#039;&#039;xfs_db(8)&#039;&#039;&#039; command to mark the problem directory for removal (see the example below). A subsequent &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; invocation will remove the directory and move all contents into &amp;quot;lost+found&amp;quot;, named by inode number (see second example on how to map inode number to directory entry name, which needs to be done _before_ removing the directory itself). The inode number of the corrupt directory is included in the shutdown report issued by the kernel on detection of directory corruption. Using that inode number, this is how one would ensure it is removed:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 # xfs_db -x /dev/sdXXX&lt;br /&gt;
 xfs_db&amp;amp;gt; inode NNN&lt;br /&gt;
 xfs_db&amp;amp;gt; print&lt;br /&gt;
 core.magic = 0x494e&lt;br /&gt;
 core.mode = 040755&lt;br /&gt;
 core.version = 2&lt;br /&gt;
 core.format = 3 (btree)&lt;br /&gt;
 ...&lt;br /&gt;
 xfs_db&amp;amp;gt; write core.mode 0&lt;br /&gt;
 xfs_db&amp;amp;gt; quit&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A subsequent &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; will clear the directory, and add new entries (named by inode number) in lost+found.&lt;br /&gt;
&lt;br /&gt;
The easiest way to map inode numbers to full paths is via &#039;&#039;&#039;xfs_ncheck(8)&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;: &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 # xfs_ncheck -i 14101 -i 14102 /dev/sdXXX&lt;br /&gt;
       14101 full/path/mumble_fratz_foo_bar_1495&lt;br /&gt;
       14102 full/path/mumble_fratz_foo_bar_1494&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Should this not work, we can manually map inode numbers in B-Tree format directory by taking the following steps:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 # xfs_db -x /dev/sdXXX&lt;br /&gt;
 xfs_db&amp;amp;gt; inode NNN&lt;br /&gt;
 xfs_db&amp;amp;gt; print&lt;br /&gt;
 core.magic = 0x494e&lt;br /&gt;
 ...&lt;br /&gt;
 next_unlinked = null&lt;br /&gt;
 u.bmbt.level = 1&lt;br /&gt;
 u.bmbt.numrecs = 1&lt;br /&gt;
 u.bmbt.keys[1] = [startoff] 1:[0]&lt;br /&gt;
 u.bmbt.ptrs[1] = 1:3628&lt;br /&gt;
 xfs_db&amp;amp;gt; fsblock 3628&lt;br /&gt;
 xfs_db&amp;amp;gt; type bmapbtd&lt;br /&gt;
 xfs_db&amp;amp;gt; print&lt;br /&gt;
 magic = 0x424d4150&lt;br /&gt;
 level = 0&lt;br /&gt;
 numrecs = 19&lt;br /&gt;
 leftsib = null&lt;br /&gt;
 rightsib = null&lt;br /&gt;
 recs[1-19] = [startoff,startblock,blockcount,extentflag]&lt;br /&gt;
        1:[0,3088,4,0] 2:[4,3128,8,0] 3:[12,3308,4,0] 4:[16,3360,4,0]&lt;br /&gt;
        5:[20,3496,8,0] 6:[28,3552,8,0] 7:[36,3624,4,0] 8:[40,3633,4,0]&lt;br /&gt;
        9:[44,3688,8,0] 10:[52,3744,4,0] 11:[56,3784,8,0]&lt;br /&gt;
        12:[64,3840,8,0] 13:[72,3896,4,0] 14:[33554432,3092,4,0]&lt;br /&gt;
        15:[33554436,3488,8,0] 16:[33554444,3629,4,0]&lt;br /&gt;
        17:[33554448,3748,4,0] 18:[33554452,3900,4,0]&lt;br /&gt;
        19:[67108864,3364,4,0]&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At this point we are looking at the extents that hold all of the directory information. There are three types of extent here, we have the data blocks (extents 1 through 13 above), then the leaf blocks (extents 14 through 18), then the freelist blocks (extent 19 above). The jumps in the first field (start offset) indicate our progression through each of the three types. For recovering file names, we are only interested in the data blocks, so we can now feed those offset numbers into the &#039;&#039;&#039;xfs_db&#039;&#039;&#039; dblock command. So, for the fifth extent - 5:[20,3496,8,0] - listed above:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
 xfs_db&amp;amp;gt; dblock 20&lt;br /&gt;
 xfs_db&amp;amp;gt; print&lt;br /&gt;
 dhdr.magic = 0x58443244&lt;br /&gt;
 dhdr.bestfree[0].offset = 0&lt;br /&gt;
 dhdr.bestfree[0].length = 0&lt;br /&gt;
 dhdr.bestfree[1].offset = 0&lt;br /&gt;
 dhdr.bestfree[1].length = 0&lt;br /&gt;
 dhdr.bestfree[2].offset = 0&lt;br /&gt;
 dhdr.bestfree[2].length = 0&lt;br /&gt;
 du[0].inumber = 13937&lt;br /&gt;
 du[0].namelen = 25&lt;br /&gt;
 du[0].name = &amp;quot;mumble_fratz_foo_bar_1595&amp;quot;&lt;br /&gt;
 du[0].tag = 0x10&lt;br /&gt;
 du[1].inumber = 13938&lt;br /&gt;
 du[1].namelen = 25&lt;br /&gt;
 du[1].name = &amp;quot;mumble_fratz_foo_bar_1594&amp;quot;&lt;br /&gt;
 du[1].tag = 0x38&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
So, here we can see that inode number 13938 matches up with name &amp;quot;mumble_fratz_foo_bar_1594&amp;quot;. Iterate through all the extents, and extract all the name-to-inode-number mappings you can, as these will be useful when looking at &amp;quot;lost+found&amp;quot; (once &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; has removed the corrupt directory).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Q: Why does my &amp;gt; 2TB XFS partition disappear when I reboot ? ==&lt;br /&gt;
&lt;br /&gt;
Strictly speaking this is not an XFS problem.&lt;br /&gt;
&lt;br /&gt;
To support &amp;gt; 2TB partitions you need two things: a kernel that supports large block devices (&amp;lt;tt&amp;gt;CONFIG_LBD=y&amp;lt;/tt&amp;gt;) and a partition table format that can hold large partitions.  The default DOS partition tables don&#039;t.  The best partition format for&lt;br /&gt;
&amp;gt; 2TB partitions is the EFI GPT format (&amp;lt;tt&amp;gt;CONFIG_EFI_PARTITION=y&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Without CONFIG_LBD=y you can&#039;t even create the filesystem, but without &amp;lt;tt&amp;gt;CONFIG_EFI_PARTITION=y&amp;lt;/tt&amp;gt; it works fine until you reboot at which point the partition will disappear.  Note that you need to enable the &amp;lt;tt&amp;gt;CONFIG_PARTITION_ADVANCED&amp;lt;/tt&amp;gt; option before you can set &amp;lt;tt&amp;gt;CONFIG_EFI_PARTITION=y&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Q: Why do I receive &amp;lt;tt&amp;gt;No space left on device&amp;lt;/tt&amp;gt; after &amp;lt;tt&amp;gt;xfs_growfs&amp;lt;/tt&amp;gt;? ==&lt;br /&gt;
&lt;br /&gt;
After [http://oss.sgi.com/pipermail/xfs/2009-January/039828.html growing a XFS filesystem], df(1) would show enough free space but attempts to write to the filesystem result in -ENOSPC. To fix this, [http://oss.sgi.com/pipermail/xfs/2009-January/039835.html Dave Chinner advised]:&lt;br /&gt;
&lt;br /&gt;
  The only way to fix this is to move data around to free up space&lt;br /&gt;
  below 1TB. Find your oldest data (i.e. that was around before even&lt;br /&gt;
  the first grow) and move it off the filesystem (move, not copy).&lt;br /&gt;
  Then if you copy it back on, the data blocks will end up above 1TB&lt;br /&gt;
  and that should leave you with plenty of space for inodes below 1TB.&lt;br /&gt;
  &lt;br /&gt;
  A complete dump and restore will also fix the problem ;)&lt;br /&gt;
&lt;br /&gt;
Also, you can add &#039;inode64&#039; to your mount options to allow inodes to live above 1TB.&lt;br /&gt;
&lt;br /&gt;
example:[https://www.centos.org/modules/newbb/viewtopic.php?topic_id=30703&amp;amp;forum=38 | No space left on device on xfs filesystem with 7.7TB free]&lt;br /&gt;
&lt;br /&gt;
== Q: Is using noatime or/and nodiratime at mount time giving any performance benefits in xfs (or not using them performance decrease)? ==&lt;br /&gt;
&lt;br /&gt;
The default atime behaviour is relatime, which has almost no overhead compared to noatime but still maintains sane atime values. All Linux filesystems use this as the default now (since around 2.6.30), but XFS has used relatime-like behaviour since 2006, so no-one should really need to ever use noatime on XFS for performance reasons. &lt;br /&gt;
&lt;br /&gt;
Also, noatime implies nodiratime, so there is never a need to specify nodiratime when noatime is also specified.&lt;br /&gt;
&lt;br /&gt;
== Q: How to get around a bad inode repair is unable to clean up ==&lt;br /&gt;
&lt;br /&gt;
The trick is go in with xfs_db and mark the inode as a deleted, which will cause repair to clean it up and finish the remove process.&lt;br /&gt;
&lt;br /&gt;
  xfs_db -x -c &#039;inode XXX&#039; -c &#039;write core.nextents 0&#039; -c &#039;write core.size 0&#039; /dev/hdXX&lt;br /&gt;
&lt;br /&gt;
== Q: How to calculate the correct sunit,swidth values for optimal performance ==&lt;br /&gt;
&lt;br /&gt;
XFS allows to optimize for a given RAID stripe unit (stripe size) and stripe width (number of data disks) via mount options.&lt;br /&gt;
&lt;br /&gt;
These options can be sometimes autodetected (for example with md raid and recent enough kernel (&amp;gt;= 2.6.32) and xfsprogs (&amp;gt;= 3.1.1) built with libblkid support) but manual calculation is needed for most of hardware raids.&lt;br /&gt;
&lt;br /&gt;
The calculation of these values is quite simple:&lt;br /&gt;
&lt;br /&gt;
  su = &amp;lt;RAID controllers stripe size in BYTES (or KiBytes when used with k)&amp;gt;&lt;br /&gt;
  sw = &amp;lt;# of data disks (don&#039;t count parity disks)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So if your RAID controller has a stripe size of 64KB, and you have a RAID-6 with 8 disks, use&lt;br /&gt;
&lt;br /&gt;
  su = 64k&lt;br /&gt;
  sw = 6 (RAID-6 of 8 disks has 6 data disks)&lt;br /&gt;
&lt;br /&gt;
A RAID stripe size of 256KB with a RAID-10 over 16 disks should use&lt;br /&gt;
&lt;br /&gt;
  su = 256k&lt;br /&gt;
  sw = 8 (RAID-10 of 16 disks has 8 data disks)&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can use &amp;quot;sunit&amp;quot; instead of &amp;quot;su&amp;quot; and &amp;quot;swidth&amp;quot; instead of &amp;quot;sw&amp;quot; but then sunit/swidth values need to be specified in &amp;quot;number of 512B sectors&amp;quot;!&lt;br /&gt;
&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;xfs_info&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;mkfs.xfs&amp;lt;/tt&amp;gt; interpret sunit and swidth as being specified in units of 512B sectors; that&#039;s unfortunately not the unit they&#039;re reported in, however.&lt;br /&gt;
&amp;lt;tt&amp;gt;xfs_info&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;mkfs.xfs&amp;lt;/tt&amp;gt; report them in multiples of your basic block size (bsize) and not in 512B sectors.&lt;br /&gt;
&lt;br /&gt;
Assume for example: swidth 1024 (specified at mkfs.xfs command line; so 1024 of 512B sectors) and block size of 4096 (bsize reported by mkfs.xfs at output). You should see swidth 128 (reported by mkfs.xfs at output). 128 * 4096 == 1024 * 512.&lt;br /&gt;
&lt;br /&gt;
When creating XFS filesystem on top of LVM on top of hardware raid please use sunit/swith values as when creating XFS filesystem directly on top of hardware raid.&lt;br /&gt;
&lt;br /&gt;
== Q: Why doesn&#039;t NFS-exporting subdirectories of inode64-mounted filesystem work? ==&lt;br /&gt;
&lt;br /&gt;
The default &amp;lt;tt&amp;gt;fsid&amp;lt;/tt&amp;gt; type encodes only 32-bit of the inode number for subdirectory exports.  However, exporting the root of the filesystem works, or using one of the non-default &amp;lt;tt&amp;gt;fsid&amp;lt;/tt&amp;gt; types (&amp;lt;tt&amp;gt;fsid=uuid&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;/etc/exports&amp;lt;/tt&amp;gt; with recent &amp;lt;tt&amp;gt;nfs-utils&amp;lt;/tt&amp;gt;) should work as well. (Thanks, Christoph!)&lt;br /&gt;
&lt;br /&gt;
== Q: What is the inode64 mount option for? ==&lt;br /&gt;
&lt;br /&gt;
By default, with 32bit inodes, XFS places inodes only in the first 1TB of a disk. If you have a disk with 100TB, all inodes will be stuck in the first TB. This can lead to strange things like &amp;quot;disk full&amp;quot; when you still have plenty space free, but there&#039;s no more place in the first TB to create a new inode. Also, performance sucks.&lt;br /&gt;
&lt;br /&gt;
To come around this, use the inode64 mount options for filesystems &amp;gt;1TB. Inodes will then be placed in the location where their data is, minimizing disk seeks.&lt;br /&gt;
&lt;br /&gt;
Beware that some old programs might have problems reading 64bit inodes, especially over NFS. Your editor used inode64 for over a year with recent (openSUSE 11.1 and higher) distributions using NFS and Samba without any corruptions, so that might be a recent enough distro.&lt;br /&gt;
&lt;br /&gt;
== Q: Can I just try the inode64 option to see if it helps me? ==&lt;br /&gt;
&lt;br /&gt;
Starting from kernel 2.6.35, you can try and then switch back. Older kernels have a bug leading to strange problems if you mount without inode64 again. For example, you can&#039;t access files &amp;amp; dirs that have been created with an inode &amp;gt;32bit anymore.&lt;br /&gt;
&lt;br /&gt;
== Q: Performance: mkfs.xfs -n size=64k option ==&lt;br /&gt;
&lt;br /&gt;
Asking the implications of that mkfs option on the XFS mailing list, Dave Chinner explained it this way:&lt;br /&gt;
&lt;br /&gt;
Inodes are not stored in the directory structure, only the directory entry name and the inode number. Hence the amount of space used by a&lt;br /&gt;
directory entry is determined by the length of the name.&lt;br /&gt;
&lt;br /&gt;
There is extra overhead to allocate large directory blocks (16 pages instead of one, to begin with, then there&#039;s the vmap overhead, etc), so for small directories smaller block sizes are faster for create and unlink operations.&lt;br /&gt;
&lt;br /&gt;
For empty directories, operations on 4k block sized directories consume roughly 50% less CPU that 64k block size directories. The 4k block size directories consume less CPU out to roughly 1.5 million entries where the two are roughly equal. At directory sizes of 10 million entries, 64k directory block operations are consuming about 15% of the CPU that 4k directory block operations consume.&lt;br /&gt;
&lt;br /&gt;
In terms of lookups, the 64k block directory will take less IO but consume more CPU for a given lookup. Hence it depends on your IO latency and whether directory readahead can hide that latency as to which will be faster. e.g. For SSDs, CPU usage might be the limiting factor, not the IO. Right now I don&#039;t have any numbers on what the difference might be - I&#039;m getting 1 billion inode population issues worked out first before I start on measuring cold cache lookup times on 1 billion files....&lt;br /&gt;
&lt;br /&gt;
== Q: I want to tune my XFS filesystems for &amp;lt;something&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
The standard answer you will get to this question is this: use the defaults.&lt;br /&gt;
&lt;br /&gt;
There are few workloads where using non-default mkfs.xfs or mount options make much sense. In general, the default values already used are optimised for best performance in the first place. mkfs.xfs will detect the difference between single disk and MD/DM RAID setups and change the default values it uses to  configure the filesystem appropriately.&lt;br /&gt;
&lt;br /&gt;
There are a lot of &amp;quot;XFS tuning guides&amp;quot; that Google will find for you - most are old, out of date and full of misleading or just plain incorrect information. Don&#039;t expect that tuning your filesystem for optimal bonnie++ numbers will mean your workload will go faster. You should only consider changing the defaults if either: a) you know from experience that your workload causes XFS a specific problem that can be worked around via a configuration change, or b) your workload is demonstrating bad performance when using the default configurations. In this case, you need to understand why your application is causing bad performance before you start tweaking XFS configurations.&lt;br /&gt;
&lt;br /&gt;
In most cases, the only thing you need to to consider for &amp;lt;tt&amp;gt;mkfs.xfs&amp;lt;/tt&amp;gt; is specifying the stripe unit and width for hardware RAID devices. For mount options, the only thing that will change metadata performance considerably are the &amp;lt;tt&amp;gt;logbsize&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;delaylog&amp;lt;/tt&amp;gt; mount options. Increasing &amp;lt;tt&amp;gt;logbsize&amp;lt;/tt&amp;gt; reduces the number of journal IOs for a given workload, and &amp;lt;tt&amp;gt;delaylog&amp;lt;/tt&amp;gt; will reduce them even further. The trade off for this increase in metadata performance is that more operations may be &amp;quot;missing&amp;quot; after recovery if the system crashes while actively making modifications.&lt;br /&gt;
&lt;br /&gt;
As of kernel 3.2.12, the default i/o scheduler, CFQ, will defeat much of the parallelization in XFS.&lt;br /&gt;
&lt;br /&gt;
== Q: Which factors influence the memory usage of xfs_repair? ==&lt;br /&gt;
&lt;br /&gt;
This is best explained with an example. The example filesystem is 16Tb, but basically empty (look at icount).&lt;br /&gt;
&lt;br /&gt;
  # xfs_repair -n -vv -m 1 /dev/vda&lt;br /&gt;
  Phase 1 - find and verify superblock...&lt;br /&gt;
          - max_mem = 1024, icount = 64, imem = 0, dblock = 4294967296, dmem = 2097152&lt;br /&gt;
  Required memory for repair is greater that the maximum specified&lt;br /&gt;
  with the -m option. Please increase it to at least 2096.&lt;br /&gt;
  #&lt;br /&gt;
&lt;br /&gt;
xfs_repair is saying it needs at least 2096MB of RAM to repair the filesystem,&lt;br /&gt;
of which 2,097,152KB is needed for tracking free space. &lt;br /&gt;
(The -m 1 argument was telling xfs_repair to use ony 1 MB of memory.)&lt;br /&gt;
&lt;br /&gt;
Now if we add some inodes (50 million) to the filesystem (look at icount again), and the result is:&lt;br /&gt;
&lt;br /&gt;
  # xfs_repair -vv -m 1 /dev/vda&lt;br /&gt;
  Phase 1 - find and verify superblock...&lt;br /&gt;
          - max_mem = 1024, icount = 50401792, imem = 196882, dblock = 4294967296, dmem = 2097152&lt;br /&gt;
  Required memory for repair is greater that the maximum specified&lt;br /&gt;
  with the -m option. Please increase it to at least 2289.&lt;br /&gt;
&lt;br /&gt;
That is now needs at least another 200MB of RAM to run.&lt;br /&gt;
&lt;br /&gt;
The numbers reported by xfs_repair are the absolute minimum required and approximate at that;&lt;br /&gt;
more RAM than this may be required to complete successfully.&lt;br /&gt;
Also, if you only give xfs_repair the minimum required RAM, it will be slow;&lt;br /&gt;
for best repair performance, the more RAM you can give it the better.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Q: Why some files of my filesystem shows as &amp;quot;?????????? ? ?      ?          ?                ? filename&amp;quot; ? ==&lt;br /&gt;
&lt;br /&gt;
If ls -l shows you a listing as&lt;br /&gt;
&lt;br /&gt;
  # ?????????? ? ?      ?          ?                ? file1&lt;br /&gt;
    ?????????? ? ?      ?          ?                ? file2&lt;br /&gt;
    ?????????? ? ?      ?          ?                ? file3&lt;br /&gt;
    ?????????? ? ?      ?          ?                ? file4&lt;br /&gt;
&lt;br /&gt;
and errors like:&lt;br /&gt;
  # ls /pathtodir/&lt;br /&gt;
    ls: cannot access /pathtodir/file1: Invalid argument&lt;br /&gt;
    ls: cannot access /pathtodir/file2: Invalid argument&lt;br /&gt;
    ls: cannot access /pathtodir/file3: Invalid argument&lt;br /&gt;
    ls: cannot access /pathtodir/file4: Invalid argument&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
or even:&lt;br /&gt;
  # failed to stat /pathtodir/file1&lt;br /&gt;
&lt;br /&gt;
It is very probable your filesystem must be mounted with inode64&lt;br /&gt;
  # mount -oremount,inode64 /dev/diskpart /mnt/xfs&lt;br /&gt;
&lt;br /&gt;
should make it work ok again.&lt;br /&gt;
If it works, add the option to fstab.&lt;br /&gt;
&lt;br /&gt;
== Q: The xfs_db &amp;quot;frag&amp;quot; command says I&#039;m over 50%.  Is that bad? ==&lt;br /&gt;
&lt;br /&gt;
It depends.  It&#039;s important to know how the value is calculated.  xfs_db looks at the extents in all files, and returns:&lt;br /&gt;
&lt;br /&gt;
  (actual extents - ideal extents) / actual extents&lt;br /&gt;
&lt;br /&gt;
This means that if, for example, you have an average of 2 extents per file, you&#039;ll get an answer of 50%.  4 extents per file would give you 75%.  This may or may not be a problem, especially depending on the size of the files in question.  (i.e. 400GB files in four 100GB extents would hardly be considered badly fragmented).  The xfs_bmap command can be useful for displaying the actual fragmentation/layout of individual files.&lt;br /&gt;
&lt;br /&gt;
Note that above a few average extents per file, the fragmentation factor rapidly approaches 100%:&lt;br /&gt;
[[Image:Frag_factor.png|500px]]&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=XFS_Papers_and_Documentation&amp;diff=2408</id>
		<title>XFS Papers and Documentation</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=XFS_Papers_and_Documentation&amp;diff=2408"/>
		<updated>2012-01-30T03:43:31Z</updated>

		<summary type="html">&lt;p&gt;Dgc: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Primary XFS Documentation ===&lt;br /&gt;
&lt;br /&gt;
The XFS documentation started by SGI has been converted to docbook/[https://fedorahosted.org/publican/ Publican] format.  The material is suitable for experienced users as well as developers and support staff.  The XML source is available in a [http://git.kernel.org/?p=fs/xfs/xfsdocs-xml-dev.git;a=summary git repository] and builds of the documentation are available here:&lt;br /&gt;
&lt;br /&gt;
* [http://xfs.org/docs/xfsdocs-xml-dev/XFS_User_Guide//tmp/en-US/html/index.html XFS User Guide]&lt;br /&gt;
&lt;br /&gt;
* [http://xfs.org/docs/xfsdocs-xml-dev/XFS_Filesystem_Structure//tmp/en-US/html/index.html XFS File System Structure]&lt;br /&gt;
** [http://sites.google.com/site/kandamotohiro/xfs Japanese translation] is also available.&lt;br /&gt;
&lt;br /&gt;
* [http://xfs.org/docs/xfsdocs-xml-dev/XFS_Labs/tmp/en-US/html/index.html XFS Training Labs]&lt;br /&gt;
&lt;br /&gt;
* (Original versions of this material are still available at [http://oss.sgi.com/projects/xfs/training/index.html XFS Overview and Internals (html)] and [http://oss.sgi.com/projects/xfs/papers/xfs_filesystem_structure.pdf XFS Filesystem Structure (pdf)]&lt;br /&gt;
&lt;br /&gt;
The format of &amp;lt;tt&amp;gt;/proc/fs/xfs/stat&amp;lt;/tt&amp;gt; also has been documented:&lt;br /&gt;
* [[Runtime_Stats|Runtime_Stats]]&lt;br /&gt;
&lt;br /&gt;
=== Papers, Presentations, Etc ===&lt;br /&gt;
&lt;br /&gt;
At the linux.conf.au 2012 event, Dave Chinner presented a talk on filesystem metadata scalability:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;XFS - Recent and Future Adventures in Filesystem Scalability&#039;&#039; [[http://www.youtube.com/watch?v=FegjLbCnoBw Video]] [[http://xfs.org/images/d/d1/Xfs-scalability-lca2012.pdf Presentation Slides]]&lt;br /&gt;
&lt;br /&gt;
The October 2009 issue of the USENIX ;login: magazine published an article about XFS targeted at system administrators:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;XFS: The big storage file system for Linux&#039;&#039; [[http://oss.sgi.com/projects/xfs/papers/hellwig.pdf pdf]]&lt;br /&gt;
&lt;br /&gt;
At the Ottawa Linux Symposium (July 2006), Dave Chinner presented a paper on filesystem scalability in Linux 2.6 kernels:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;High Bandwidth Filesystems on Large Systems&#039;&#039; (July 2006) [[http://oss.sgi.com/projects/xfs/papers/ols2006/ols-2006-paper.pdf paper]] [[http://oss.sgi.com/projects/xfs/papers/ols2006/ols-2006-presentation.pdf presentation]]&lt;br /&gt;
&lt;br /&gt;
At linux.conf.au 2008 Dave Chinner gave a presentation about xfs_repair that he co-authored with Barry Naujok:&lt;br /&gt;
&lt;br /&gt;
* Fixing XFS Filesystems Faster [[http://mirror.linux.org.au/pub/linux.conf.au/2008/slides/135-fixing_xfs_faster.pdf pdf]]&lt;br /&gt;
&lt;br /&gt;
In July 2006, SGI storage marketing updated the XFS datasheet:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;Open Source XFS for Linux&#039;&#039; [[http://oss.sgi.com/projects/xfs/datasheet.pdf pdf]]&lt;br /&gt;
&lt;br /&gt;
At UKUUG 2003, Christoph Hellwig presented a talk on XFS:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;XFS for Linux&#039;&#039; (July 2003) [[http://oss.sgi.com/projects/xfs/papers/ukuug2003.pdf pdf]] [[http://verein.lst.de/~hch/talks/ukuug2003/ html]]&lt;br /&gt;
&lt;br /&gt;
Originally published in Proceedings of the FREENIX Track: 2002 Usenix Annual Technical Conference:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;Filesystem Performance and Scalability in Linux 2.4.17&#039;&#039; (June 2002) [[http://oss.sgi.com/projects/xfs/papers/filesystem-perf-tm.pdf pdf]]&lt;br /&gt;
&lt;br /&gt;
At the Ottawa Linux Symposium, an updated presentation on porting XFSÂ to Linux was given:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;Porting XFS to Linux&#039;&#039; (July 2000) [[http://oss.sgi.com/projects/xfs/papers/ols2000/ols-xfs.htm html]]&lt;br /&gt;
&lt;br /&gt;
At the Atlanta Linux Showcase, SGI presented the following paper on the port of XFS to Linux:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;Porting the SGI XFS File System to Linux&#039;&#039; (October 1999) [[http://oss.sgi.com/projects/xfs/papers/als/als.ps ps]] [[http://oss.sgi.com/projects/xfs/papers/als/als.pdf pdf]]&lt;br /&gt;
&lt;br /&gt;
At the 6th Linux Kongress &amp;amp;amp; the Linux Storage Management Workshop (LSMW) in Germany in September, 1999, SGI had a few presentations including the following:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;SGI&#039;s port of XFS to Linux&#039;&#039; (September 1999) [[http://oss.sgi.com/projects/xfs/papers/linux_kongress/index.htm html]]&lt;br /&gt;
* &#039;&#039;Overview of DMF&#039;&#039; (September 1999) [[http://oss.sgi.com/projects/xfs/papers/DMF-over/index.htm html]]&lt;br /&gt;
&lt;br /&gt;
At the LinuxWorld Conference &amp;amp;amp; Expo in August 1999, SGI published:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;An Open Source XFS data sheet&#039;&#039; (August 1999) [[http://oss.sgi.com/projects/xfs/papers/xfs_GPL.pdf pdf]]&lt;br /&gt;
&lt;br /&gt;
From the 1996 USENIX conference:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;An XFS white paper&#039;&#039; [[http://oss.sgi.com/projects/xfs/papers/xfs_usenix/index.html html]]&lt;br /&gt;
&lt;br /&gt;
=== Other historical articles, press-releases, etc ===&lt;br /&gt;
&lt;br /&gt;
* IBM&#039;s &#039;&#039;Advanced Filesystem Implementor&#039;s Guide&#039;&#039; has a chapter &#039;&#039;Introducing XFS&#039;&#039; [[http://www-106.ibm.com/developerworks/library/l-fs9.html html]]&lt;br /&gt;
&lt;br /&gt;
* An editorial titled &#039;&#039;Tired of fscking? Try a journaling filesystem!&#039;&#039;, Freshmeat (February 2001) [[http://freshmeat.net/articles/view/212/ html]]&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;Who give a fsck about filesystems&#039;&#039; provides an overview of the Linux 2.4 filesystems [[http://www.linuxuser.co.uk/articles/issue6/lu6-All_you_need_to_know_about-Filesystems.pdf html]]&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;Journal File Systems&#039;&#039; in issue 55 of &#039;&#039;Linux Gazette&#039;&#039; provides a comparison of journaled filesystems.&lt;br /&gt;
&lt;br /&gt;
* The original XFS beta release announcement was published in &#039;&#039;Linux Today&#039;&#039; (September 2000) [[http://linuxtoday.com/news_story.php3?ltsn=2000-09-26-017-04-OS-SW html]]&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;XFS: It&#039;s worth the wait&#039;&#039; was published on &#039;&#039;EarthWeb&#039;&#039; (July 2000) [[http://networking.earthweb.com/netos/oslin/article/0,,12284_623661,00.html html]]&lt;br /&gt;
&lt;br /&gt;
* An &#039;&#039;IRIX-XFS data sheet&#039;&#039; (July 1999) [[http://oss.sgi.com/projects/xfs/papers/IRIX_xfs_data_sheet.pdf pdf]]&lt;br /&gt;
&lt;br /&gt;
* The &#039;&#039;Getting Started with XFS&#039;&#039; book (1994) [[http://oss.sgi.com/projects/xfs/papers/getting_started_with_xfs.pdf pdf]]&lt;br /&gt;
&lt;br /&gt;
* Original &#039;&#039;XFS design documents&#039;&#039; (1993) ([http://oss.sgi.com/projects/xfs/design_docs/xfsdocs93_ps/ ps], [http://oss.sgi.com/projects/xfs/design_docs/xfsdocs93_pdf/ pdf])&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=File:Xfs-scalability-lca2012.pdf&amp;diff=2407</id>
		<title>File:Xfs-scalability-lca2012.pdf</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=File:Xfs-scalability-lca2012.pdf&amp;diff=2407"/>
		<updated>2012-01-30T03:37:30Z</updated>

		<summary type="html">&lt;p&gt;Dgc: Slides to LCA 2012 presentation &amp;quot;XFS - Adventures in Scalability&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Slides to LCA 2012 presentation &amp;quot;XFS - Adventures in Scalability&amp;quot;&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=FITRIM/discard&amp;diff=2361</id>
		<title>FITRIM/discard</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=FITRIM/discard&amp;diff=2361"/>
		<updated>2011-10-11T22:30:46Z</updated>

		<summary type="html">&lt;p&gt;Dgc: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Purpose ==&lt;br /&gt;
&lt;br /&gt;
FITRIM is a mounted filesystem feature to discard (or &amp;quot;[http://en.wikipedia.org/wiki/TRIM trim]&amp;quot;) blocks which are not in use by the filesystem. This is useful for solid-state drives (SSDs) and thinly-provisioned storage.&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
#The block device underneath the filesystem must support the FITRIM operation.&lt;br /&gt;
#The kernel must include TRIM support and XFS must include FITRIM support (this has been true for Linux since v2.6.38, Jan 18 2011)&lt;br /&gt;
#Realtime discard mode requires a more recent v3.0 kernel&lt;br /&gt;
&lt;br /&gt;
This can be verified by viewing /sys/block/&amp;lt;dev&amp;gt;/queue/discard_max_bytes -- If the value is zero then your device doesn&#039;t support discard&lt;br /&gt;
operations.&lt;br /&gt;
&lt;br /&gt;
== Modes of Operation ==&lt;br /&gt;
&lt;br /&gt;
* Realtime discard -- As files are removed, the filesystem issues discard requests automatically&lt;br /&gt;
* Batch Mode -- A user procedure that trims all or portions of the filesystem&lt;br /&gt;
&lt;br /&gt;
=== Realtime discard ===&lt;br /&gt;
&lt;br /&gt;
This mode issues discard requests automatically as files are removed from the filesystem.  No other command or process is required.&lt;br /&gt;
&lt;br /&gt;
Realtime discard is selected by adding the filesystem option &amp;lt;code&amp;gt;discard&amp;lt;/code&amp;gt; while mounting.&lt;br /&gt;
&lt;br /&gt;
This can be done by the following examples:&lt;br /&gt;
&lt;br /&gt;
# placing &amp;lt;code&amp;gt;discard&amp;lt;/code&amp;gt; in your /etc/fstab for the filesystem: &amp;lt;code&amp;gt;/dev/sda1 /mountpoint xfs defaults,discard 0 1&amp;lt;/code&amp;gt;&lt;br /&gt;
# mount options: &amp;lt;code&amp;gt;mount -o discard /dev/sda1 /mountpoint&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Batch Mode ===&lt;br /&gt;
&lt;br /&gt;
This mode requires user intervention.  This intervention is in the form of the command &amp;lt;code&amp;gt;fstrim&amp;lt;/code&amp;gt;.  It has been included in [http://en.wikipedia.org/wiki/Util-linux util-linux-ng] since about Nov 26, 2010.&lt;br /&gt;
&lt;br /&gt;
Usage example:&lt;br /&gt;
&amp;lt;code&amp;gt;fstrim /mountpoint&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
# FITRIM description - Lukas Czerner &amp;lt;lczerner at redhat.com&amp;gt; http://patchwork.xfs.org/patch/1490/&lt;br /&gt;
# Block requirements - Dave Chinner &amp;lt;david at fromorbit.com&amp;gt; http://oss.sgi.com/pipermail/xfs/2011-October/053379.html&lt;br /&gt;
# util-linux-ng addition - Karel Zak &amp;lt;kzak@xxxxxxxxxx&amp;gt; http://www.spinics.net/lists/util-linux-ng/msg03646.html&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=Improving_Metadata_Performance_By_Reducing_Journal_Overhead&amp;diff=2138</id>
		<title>Improving Metadata Performance By Reducing Journal Overhead</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=Improving_Metadata_Performance_By_Reducing_Journal_Overhead&amp;diff=2138"/>
		<updated>2010-12-23T04:07:09Z</updated>

		<summary type="html">&lt;p&gt;Dgc: /* Improving Metadata Performance By Reducing Journal Overhead */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Improving Metadata Performance By Reducing Journal Overhead ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
XFS currently uses asynchronous write-ahead logging to ensure that changes to&lt;br /&gt;
the filesystem structure are preserved on crash.  It does this by logging&lt;br /&gt;
detailed records of the changes being made to each object on disk during a&lt;br /&gt;
transaction. Every byte that is modified needs to be recorded in the journal.&lt;br /&gt;
&lt;br /&gt;
There are two issues with this approach. The first is that transactions can&lt;br /&gt;
modify a *lot* of metadata  to complete a single operation. Worse is the fact&lt;br /&gt;
that the average size of a transactions grows as structures get larger and&lt;br /&gt;
deeper, so performance on larger, fuller filesystem drops off as log bandwidth&lt;br /&gt;
is consumed by fewer, larger transactions.&lt;br /&gt;
&lt;br /&gt;
The second is that we re-log previous changes that are active in the journal&lt;br /&gt;
if the object is modified again. hence if an object is modified repeatedly, the&lt;br /&gt;
dirty parts of the object get rewritten over and over again. in the worst case,&lt;br /&gt;
frequently logged buffers will be entirely dirty and so even if we only change&lt;br /&gt;
a single byte in the buffer we&#039;ll log the entire buffer.&lt;br /&gt;
&lt;br /&gt;
The problem can be approached along two different axes:&lt;br /&gt;
&lt;br /&gt;
	- reduce the amount we log in a given transaction&lt;br /&gt;
	- change the way we re-log objects.&lt;br /&gt;
&lt;br /&gt;
Both of these things give the same end result - we require less bandwidth to&lt;br /&gt;
the journal to log changes that are happening in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Asynchronous Transaction Aggregation ==&lt;br /&gt;
&lt;br /&gt;
Status: Done, known as delayed logging.&lt;br /&gt;
&lt;br /&gt;
Experimental in 2.6.35, stable for production in 2.6.37, planned for default&lt;br /&gt;
in 2.6.39.&lt;br /&gt;
&lt;br /&gt;
Design documentation can be found here:&lt;br /&gt;
&lt;br /&gt;
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/filesystems/xfs-delayed-logging-design.txt&lt;br /&gt;
&lt;br /&gt;
== Atomic Multi-Transaction Operations ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A feature asynchronous transaction aggregation makes possible is atomic&lt;br /&gt;
multi-transaction operations.  On the first transaction we hold the queue in&lt;br /&gt;
memory, preventing it from being committed. We can then do further transactions&lt;br /&gt;
that will end up in the same commit record, and on the final transaction we&lt;br /&gt;
unlock the async transaction queue. This will allow all those transaction to be&lt;br /&gt;
applied atomically. This is far simpler than any other method I&#039;ve been looking&lt;br /&gt;
at to do this.&lt;br /&gt;
&lt;br /&gt;
After a bit of reflection, I think this feature may be necessary for correct&lt;br /&gt;
implementation of existing logging techniques. The way we currently implement&lt;br /&gt;
rolling transactions (with permanent log reservations and rolling&lt;br /&gt;
dup/commit/re-reserve sequences) would seem to require all the commits in a&lt;br /&gt;
rolling transaction to be including in a single commit record.  If I understand&lt;br /&gt;
history and the original design correctly, these rolling transactions were&lt;br /&gt;
implemented so that large, complex transactions would not pin the tail of the&lt;br /&gt;
log as they progressed.  IOWs, they implicitly use re-logging to keep the tail&lt;br /&gt;
of the log moving forward as they progress and continue to modify items in the&lt;br /&gt;
transaction.&lt;br /&gt;
&lt;br /&gt;
Given we are using asynchronous transaction aggregation as a method of reducing&lt;br /&gt;
re-logging, it would make sense to prevent these sorts of transactions from&lt;br /&gt;
pinning the tail of the log at all. Further, because we are effectively&lt;br /&gt;
disturbing the concept of unique transactions, I don&#039;t think that allowing a&lt;br /&gt;
rolling transaction to span aggregated commits is valid as we are going to be&lt;br /&gt;
ignoring the transaction IDs that are used to identify individual transactions.&lt;br /&gt;
&lt;br /&gt;
Hence I think it is a good idea to simply replace rolling transactions with&lt;br /&gt;
atomic multi-transaction operations. This may also allow us to split some of&lt;br /&gt;
the large compound transactions into smaller, more self contained transactions.&lt;br /&gt;
This would reduce reservation pressure on log space in the common case where&lt;br /&gt;
all the corner cases in the transactions are not taken. In terms of&lt;br /&gt;
implementation, I think we can initially augment the permanent transaction&lt;br /&gt;
reservation/release interface to acheive this. With a working implementation,&lt;br /&gt;
we can then look to changing to a more explicit interface and slowly work to&lt;br /&gt;
remove the &#039;permanent log transaction&#039; concept entirely. This shold simplify&lt;br /&gt;
the log code somewhat....&lt;br /&gt;
&lt;br /&gt;
Note: This asynchronous transaction aggregation is originally based on a&lt;br /&gt;
concept floated by Nathan Scott called &#039;Delayed Logging&#039; after observing how&lt;br /&gt;
ext3 implemented journalling.  This never passed more than a concept&lt;br /&gt;
description phase....&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Operation Based Logging ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The second approach to reducing log traffic is to change exactly what we&lt;br /&gt;
log in the transactions. At the moment, what we log is the exact change to&lt;br /&gt;
the item that is being made. For things like inodes and dquots, this isn&#039;t&lt;br /&gt;
particularly expensive because it is already a very compact form. The issue&lt;br /&gt;
comes with changes that are logged in buffers.&lt;br /&gt;
&lt;br /&gt;
The prime example of this is a btree modification that involves either removing&lt;br /&gt;
or inserting a record into a buffer. The records are kept in compact form, so an&lt;br /&gt;
insert or remove will also move other records around in the buffer. In the worst&lt;br /&gt;
case, a single insert or remove of a 16 byte record can dirty an entire block&lt;br /&gt;
(4k generally, but could be up to 64k). In this case, if we were to log the&lt;br /&gt;
btree operation (e.g. insert {record, index}) rather than the resultant change&lt;br /&gt;
on the buffer the overhead of a btree operation is fixed. Such logging also&lt;br /&gt;
allows us to avoid needing to log the changes due to splits and merges - we just&lt;br /&gt;
replay the operation and subsequent splits/merges get done as part of replay.&lt;br /&gt;
&lt;br /&gt;
The result of this is that complex transactions no longer need as much log space&lt;br /&gt;
as all possible change they can cause - we only log the basic operations that&lt;br /&gt;
are occurring and their result. Hence transaction end up being much smaller,&lt;br /&gt;
vary less in size between empty and full filesystems, etc. An example set of&lt;br /&gt;
operations describing all the changes made by an extent allocation on an inode&lt;br /&gt;
would be:&lt;br /&gt;
&lt;br /&gt;
	- inode X intent to allocate extent {off, len}&lt;br /&gt;
	- AGCNT btree update record in AG X {old rec} {new rec values}&lt;br /&gt;
	- AGBNO btree delete record in AG X {block, len}&lt;br /&gt;
	- inode X BMBT btree insert record {off, block, len}&lt;br /&gt;
	- inode X delta&lt;br /&gt;
&lt;br /&gt;
This comes down to a relatively small, bound amount of space which is close the&lt;br /&gt;
minimun and existing allocation transaction would consume.  However, with this&lt;br /&gt;
method of logging the transaction size does not increase with the size of&lt;br /&gt;
structures or the amount of updates necessary to complete the operations.&lt;br /&gt;
&lt;br /&gt;
A major difference to the existing transaction system is that re-logging&lt;br /&gt;
of items doesn&#039;t fit very neatly with operation based logging. &lt;br /&gt;
&lt;br /&gt;
There are three main disadvantages to this approach:&lt;br /&gt;
&lt;br /&gt;
	- recovery becomes more complex - it will need to change substantially&lt;br /&gt;
	  to accomodate operation replay rather than just reading from disk&lt;br /&gt;
	  and applying deltas.&lt;br /&gt;
	- we have to create a whole new set of item types and add the necessary&lt;br /&gt;
	  hooks into the code to log all the operations correctly.&lt;br /&gt;
	- re-logging is probably not possible, and that introduces &lt;br /&gt;
	  differences to the way we&#039;ll need to track objects for flushing. It&lt;br /&gt;
	  may, in fact, require transaction IDs in all objects to allow us&lt;br /&gt;
	  to determine what the last transaction that modified the item&lt;br /&gt;
	  on disk was during recovery.&lt;br /&gt;
&lt;br /&gt;
Changing the logging strategy as described is a much more fundamental change to&lt;br /&gt;
XFS than asynchronous transaction aggregation. It will be difficult to change&lt;br /&gt;
to such a model in an evolutionary manner; it is more of a &#039;flag day&#039; style&lt;br /&gt;
change where then entire functionality needs to be added in one hit. Given that&lt;br /&gt;
we will also still have to support the old log format, it doesn&#039;t enable us to&lt;br /&gt;
remove any code, either.&lt;br /&gt;
&lt;br /&gt;
Given that we are likely to see major benefits in the problem workloads as a&lt;br /&gt;
result of asynchronous transaction aggregation, it may not be necessary to&lt;br /&gt;
completely rework the transaction subsystem. Combining aggregation with an&lt;br /&gt;
ongoing process of targeted reduction of transaction size will provide benefits&lt;br /&gt;
out to at least the medium term. It is unclear whether this direction will be&lt;br /&gt;
sufficient in the long run until we can measure the benefit that aggregation&lt;br /&gt;
will provide.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Reducing Transaction Overhead ==&lt;br /&gt;
&lt;br /&gt;
Per iclog callback list locks: Done&lt;br /&gt;
&lt;br /&gt;
AIL tail pushing in it&#039;s own thread: Done&lt;br /&gt;
&lt;br /&gt;
Bulk AIL insert and delete operations: Done&lt;br /&gt;
&lt;br /&gt;
Log grant lock split-up: Done&lt;br /&gt;
&lt;br /&gt;
Lock free transaction reserve path: Done&lt;br /&gt;
&lt;br /&gt;
Moving all of the log interfacing out of the direct transaction commit path may provide similar benefits to moving the AIL pushing into it&#039;s own thread. This will mean that there will typically only be a single thread formatting and writing to iclog buffers. This will remove much of the parallelism that puts excessive pressure on many of these locks.&lt;br /&gt;
&lt;br /&gt;
== Reducing Recovery Time ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With 2GB logs, recovery can take an awfully long time due to the need&lt;br /&gt;
to read each object synchronously as we process the journal. An obvious&lt;br /&gt;
way to avoid this is to add another pass to the processing to do asynchronous&lt;br /&gt;
readahead of all the objects in the log before doing the processing passes.&lt;br /&gt;
This will populate the cache as quickly as possible and hide any read latency&lt;br /&gt;
that could occur as we process commit records.&lt;br /&gt;
&lt;br /&gt;
A logical extension to this is to sort the objects in ascending offset order&lt;br /&gt;
before issuing I/O on them. That will further optimise the readahead I/O&lt;br /&gt;
to reduce seeking and hence should speed up the read phase of recovery&lt;br /&gt;
further.&lt;br /&gt;
&lt;br /&gt;
== ToDo ==&lt;br /&gt;
Further investigation of recovery for future optimisation.&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=Improving_Metadata_Performance_By_Reducing_Journal_Overhead&amp;diff=2137</id>
		<title>Improving Metadata Performance By Reducing Journal Overhead</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=Improving_Metadata_Performance_By_Reducing_Journal_Overhead&amp;diff=2137"/>
		<updated>2010-12-23T04:03:30Z</updated>

		<summary type="html">&lt;p&gt;Dgc: /* Reducing Transaction Overhead */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Improving Metadata Performance By Reducing Journal Overhead ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
XFS currently uses asynchronous write-ahead logging to ensure that changes to&lt;br /&gt;
the filesystem structure are preserved on crash.  It does this by logging&lt;br /&gt;
detailed records of the changes being made to each object on disk during a&lt;br /&gt;
transaction. Every byte that is modified needs to be recorded in the journal.&lt;br /&gt;
&lt;br /&gt;
There are two issues with this approach. The first is that transactions can&lt;br /&gt;
modify a *lot* of metadata  to complete a single operation. Worse is the fact&lt;br /&gt;
that the average size of a transactions grows as structures get larger and&lt;br /&gt;
deeper, so performance on larger, fuller filesystem drops off as log bandwidth&lt;br /&gt;
is consumed by fewer, larger transactions.&lt;br /&gt;
&lt;br /&gt;
The second is that we re-log previous changes that are active in the journal&lt;br /&gt;
if the object is modified again. hence if an object is modified repeatedly, the&lt;br /&gt;
dirty parts of the object get rewritten over and over again. in the worst case,&lt;br /&gt;
frequently logged buffers will be entirely dirty and so even if we only change&lt;br /&gt;
a single byte in the buffer we&#039;ll log the entire buffer.&lt;br /&gt;
&lt;br /&gt;
An example of how needless this can be is the operation of a removing all the&lt;br /&gt;
files in a directory result in the directory blocks being logged over and over&lt;br /&gt;
again before finally being freed and made stale in the log. If we are freeing&lt;br /&gt;
the entire contents of the directory, the only transactions we really need in&lt;br /&gt;
the journal w.r.t to directory buffers is the &#039;remove, stale and free&#039;&lt;br /&gt;
transaction; all other changes are irrelevant because we don&#039;t care about&lt;br /&gt;
changes to free space. Depending on the directory block size, we might log each&lt;br /&gt;
directory buffer tens to hundreds of times before making it stale...&lt;br /&gt;
&lt;br /&gt;
Clearly we have two different axis to approach this problem along:&lt;br /&gt;
&lt;br /&gt;
	- reduce the amount we log in a given transaction&lt;br /&gt;
	- reduce the number of times we re-log objects.&lt;br /&gt;
&lt;br /&gt;
Both of these things give the same end result - we require less bandwidth to&lt;br /&gt;
the journal to log changes that are happening in the filesystem. Let&#039;s start&lt;br /&gt;
by looking at how to reduce re-logging of objects.&lt;br /&gt;
&lt;br /&gt;
== Asynchronous Transaction Aggregation ==&lt;br /&gt;
&lt;br /&gt;
Status: Done, known as delayed logging.&lt;br /&gt;
&lt;br /&gt;
Experimental in 2.6.35, stable for production in 2.6.37, planned for default&lt;br /&gt;
in 2.6.39.&lt;br /&gt;
&lt;br /&gt;
Design documentation can be found here:&lt;br /&gt;
&lt;br /&gt;
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/filesystems/xfs-delayed-logging-design.txt&lt;br /&gt;
&lt;br /&gt;
== Atomic Multi-Transaction Operations ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A feature asynchronous transaction aggregation makes possible is atomic&lt;br /&gt;
multi-transaction operations.  On the first transaction we hold the queue in&lt;br /&gt;
memory, preventing it from being committed. We can then do further transactions&lt;br /&gt;
that will end up in the same commit record, and on the final transaction we&lt;br /&gt;
unlock the async transaction queue. This will allow all those transaction to be&lt;br /&gt;
applied atomically. This is far simpler than any other method I&#039;ve been looking&lt;br /&gt;
at to do this.&lt;br /&gt;
&lt;br /&gt;
After a bit of reflection, I think this feature may be necessary for correct&lt;br /&gt;
implementation of existing logging techniques. The way we currently implement&lt;br /&gt;
rolling transactions (with permanent log reservations and rolling&lt;br /&gt;
dup/commit/re-reserve sequences) would seem to require all the commits in a&lt;br /&gt;
rolling transaction to be including in a single commit record.  If I understand&lt;br /&gt;
history and the original design correctly, these rolling transactions were&lt;br /&gt;
implemented so that large, complex transactions would not pin the tail of the&lt;br /&gt;
log as they progressed.  IOWs, they implicitly use re-logging to keep the tail&lt;br /&gt;
of the log moving forward as they progress and continue to modify items in the&lt;br /&gt;
transaction.&lt;br /&gt;
&lt;br /&gt;
Given we are using asynchronous transaction aggregation as a method of reducing&lt;br /&gt;
re-logging, it would make sense to prevent these sorts of transactions from&lt;br /&gt;
pinning the tail of the log at all. Further, because we are effectively&lt;br /&gt;
disturbing the concept of unique transactions, I don&#039;t think that allowing a&lt;br /&gt;
rolling transaction to span aggregated commits is valid as we are going to be&lt;br /&gt;
ignoring the transaction IDs that are used to identify individual transactions.&lt;br /&gt;
&lt;br /&gt;
Hence I think it is a good idea to simply replace rolling transactions with&lt;br /&gt;
atomic multi-transaction operations. This may also allow us to split some of&lt;br /&gt;
the large compound transactions into smaller, more self contained transactions.&lt;br /&gt;
This would reduce reservation pressure on log space in the common case where&lt;br /&gt;
all the corner cases in the transactions are not taken. In terms of&lt;br /&gt;
implementation, I think we can initially augment the permanent transaction&lt;br /&gt;
reservation/release interface to acheive this. With a working implementation,&lt;br /&gt;
we can then look to changing to a more explicit interface and slowly work to&lt;br /&gt;
remove the &#039;permanent log transaction&#039; concept entirely. This shold simplify&lt;br /&gt;
the log code somewhat....&lt;br /&gt;
&lt;br /&gt;
Note: This asynchronous transaction aggregation is originally based on a&lt;br /&gt;
concept floated by Nathan Scott called &#039;Delayed Logging&#039; after observing how&lt;br /&gt;
ext3 implemented journalling.  This never passed more than a concept&lt;br /&gt;
description phase....&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Operation Based Logging ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The second approach to reducing log traffic is to change exactly what we&lt;br /&gt;
log in the transactions. At the moment, what we log is the exact change to&lt;br /&gt;
the item that is being made. For things like inodes and dquots, this isn&#039;t&lt;br /&gt;
particularly expensive because it is already a very compact form. The issue&lt;br /&gt;
comes with changes that are logged in buffers.&lt;br /&gt;
&lt;br /&gt;
The prime example of this is a btree modification that involves either removing&lt;br /&gt;
or inserting a record into a buffer. The records are kept in compact form, so an&lt;br /&gt;
insert or remove will also move other records around in the buffer. In the worst&lt;br /&gt;
case, a single insert or remove of a 16 byte record can dirty an entire block&lt;br /&gt;
(4k generally, but could be up to 64k). In this case, if we were to log the&lt;br /&gt;
btree operation (e.g. insert {record, index}) rather than the resultant change&lt;br /&gt;
on the buffer the overhead of a btree operation is fixed. Such logging also&lt;br /&gt;
allows us to avoid needing to log the changes due to splits and merges - we just&lt;br /&gt;
replay the operation and subsequent splits/merges get done as part of replay.&lt;br /&gt;
&lt;br /&gt;
The result of this is that complex transactions no longer need as much log space&lt;br /&gt;
as all possible change they can cause - we only log the basic operations that&lt;br /&gt;
are occurring and their result. Hence transaction end up being much smaller,&lt;br /&gt;
vary less in size between empty and full filesystems, etc. An example set of&lt;br /&gt;
operations describing all the changes made by an extent allocation on an inode&lt;br /&gt;
would be:&lt;br /&gt;
&lt;br /&gt;
	- inode X intent to allocate extent {off, len}&lt;br /&gt;
	- AGCNT btree update record in AG X {old rec} {new rec values}&lt;br /&gt;
	- AGBNO btree delete record in AG X {block, len}&lt;br /&gt;
	- inode X BMBT btree insert record {off, block, len}&lt;br /&gt;
	- inode X delta&lt;br /&gt;
&lt;br /&gt;
This comes down to a relatively small, bound amount of space which is close the&lt;br /&gt;
minimun and existing allocation transaction would consume.  However, with this&lt;br /&gt;
method of logging the transaction size does not increase with the size of&lt;br /&gt;
structures or the amount of updates necessary to complete the operations.&lt;br /&gt;
&lt;br /&gt;
A major difference to the existing transaction system is that re-logging&lt;br /&gt;
of items doesn&#039;t fit very neatly with operation based logging. &lt;br /&gt;
&lt;br /&gt;
There are three main disadvantages to this approach:&lt;br /&gt;
&lt;br /&gt;
	- recovery becomes more complex - it will need to change substantially&lt;br /&gt;
	  to accomodate operation replay rather than just reading from disk&lt;br /&gt;
	  and applying deltas.&lt;br /&gt;
	- we have to create a whole new set of item types and add the necessary&lt;br /&gt;
	  hooks into the code to log all the operations correctly.&lt;br /&gt;
	- re-logging is probably not possible, and that introduces &lt;br /&gt;
	  differences to the way we&#039;ll need to track objects for flushing. It&lt;br /&gt;
	  may, in fact, require transaction IDs in all objects to allow us&lt;br /&gt;
	  to determine what the last transaction that modified the item&lt;br /&gt;
	  on disk was during recovery.&lt;br /&gt;
&lt;br /&gt;
Changing the logging strategy as described is a much more fundamental change to&lt;br /&gt;
XFS than asynchronous transaction aggregation. It will be difficult to change&lt;br /&gt;
to such a model in an evolutionary manner; it is more of a &#039;flag day&#039; style&lt;br /&gt;
change where then entire functionality needs to be added in one hit. Given that&lt;br /&gt;
we will also still have to support the old log format, it doesn&#039;t enable us to&lt;br /&gt;
remove any code, either.&lt;br /&gt;
&lt;br /&gt;
Given that we are likely to see major benefits in the problem workloads as a&lt;br /&gt;
result of asynchronous transaction aggregation, it may not be necessary to&lt;br /&gt;
completely rework the transaction subsystem. Combining aggregation with an&lt;br /&gt;
ongoing process of targeted reduction of transaction size will provide benefits&lt;br /&gt;
out to at least the medium term. It is unclear whether this direction will be&lt;br /&gt;
sufficient in the long run until we can measure the benefit that aggregation&lt;br /&gt;
will provide.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Reducing Transaction Overhead ==&lt;br /&gt;
&lt;br /&gt;
Per iclog callback list locks: Done&lt;br /&gt;
&lt;br /&gt;
AIL tail pushing in it&#039;s own thread: Done&lt;br /&gt;
&lt;br /&gt;
Bulk AIL insert and delete operations: Done&lt;br /&gt;
&lt;br /&gt;
Log grant lock split-up: Done&lt;br /&gt;
&lt;br /&gt;
Lock free transaction reserve path: Done&lt;br /&gt;
&lt;br /&gt;
Moving all of the log interfacing out of the direct transaction commit path may provide similar benefits to moving the AIL pushing into it&#039;s own thread. This will mean that there will typically only be a single thread formatting and writing to iclog buffers. This will remove much of the parallelism that puts excessive pressure on many of these locks.&lt;br /&gt;
&lt;br /&gt;
== Reducing Recovery Time ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With 2GB logs, recovery can take an awfully long time due to the need&lt;br /&gt;
to read each object synchronously as we process the journal. An obvious&lt;br /&gt;
way to avoid this is to add another pass to the processing to do asynchronous&lt;br /&gt;
readahead of all the objects in the log before doing the processing passes.&lt;br /&gt;
This will populate the cache as quickly as possible and hide any read latency&lt;br /&gt;
that could occur as we process commit records.&lt;br /&gt;
&lt;br /&gt;
A logical extension to this is to sort the objects in ascending offset order&lt;br /&gt;
before issuing I/O on them. That will further optimise the readahead I/O&lt;br /&gt;
to reduce seeking and hence should speed up the read phase of recovery&lt;br /&gt;
further.&lt;br /&gt;
&lt;br /&gt;
== ToDo ==&lt;br /&gt;
Further investigation of recovery for future optimisation.&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=Improving_Metadata_Performance_By_Reducing_Journal_Overhead&amp;diff=2136</id>
		<title>Improving Metadata Performance By Reducing Journal Overhead</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=Improving_Metadata_Performance_By_Reducing_Journal_Overhead&amp;diff=2136"/>
		<updated>2010-12-23T03:58:17Z</updated>

		<summary type="html">&lt;p&gt;Dgc: /* Asynchronous Transaction Aggregation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Improving Metadata Performance By Reducing Journal Overhead ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
XFS currently uses asynchronous write-ahead logging to ensure that changes to&lt;br /&gt;
the filesystem structure are preserved on crash.  It does this by logging&lt;br /&gt;
detailed records of the changes being made to each object on disk during a&lt;br /&gt;
transaction. Every byte that is modified needs to be recorded in the journal.&lt;br /&gt;
&lt;br /&gt;
There are two issues with this approach. The first is that transactions can&lt;br /&gt;
modify a *lot* of metadata  to complete a single operation. Worse is the fact&lt;br /&gt;
that the average size of a transactions grows as structures get larger and&lt;br /&gt;
deeper, so performance on larger, fuller filesystem drops off as log bandwidth&lt;br /&gt;
is consumed by fewer, larger transactions.&lt;br /&gt;
&lt;br /&gt;
The second is that we re-log previous changes that are active in the journal&lt;br /&gt;
if the object is modified again. hence if an object is modified repeatedly, the&lt;br /&gt;
dirty parts of the object get rewritten over and over again. in the worst case,&lt;br /&gt;
frequently logged buffers will be entirely dirty and so even if we only change&lt;br /&gt;
a single byte in the buffer we&#039;ll log the entire buffer.&lt;br /&gt;
&lt;br /&gt;
An example of how needless this can be is the operation of a removing all the&lt;br /&gt;
files in a directory result in the directory blocks being logged over and over&lt;br /&gt;
again before finally being freed and made stale in the log. If we are freeing&lt;br /&gt;
the entire contents of the directory, the only transactions we really need in&lt;br /&gt;
the journal w.r.t to directory buffers is the &#039;remove, stale and free&#039;&lt;br /&gt;
transaction; all other changes are irrelevant because we don&#039;t care about&lt;br /&gt;
changes to free space. Depending on the directory block size, we might log each&lt;br /&gt;
directory buffer tens to hundreds of times before making it stale...&lt;br /&gt;
&lt;br /&gt;
Clearly we have two different axis to approach this problem along:&lt;br /&gt;
&lt;br /&gt;
	- reduce the amount we log in a given transaction&lt;br /&gt;
	- reduce the number of times we re-log objects.&lt;br /&gt;
&lt;br /&gt;
Both of these things give the same end result - we require less bandwidth to&lt;br /&gt;
the journal to log changes that are happening in the filesystem. Let&#039;s start&lt;br /&gt;
by looking at how to reduce re-logging of objects.&lt;br /&gt;
&lt;br /&gt;
== Asynchronous Transaction Aggregation ==&lt;br /&gt;
&lt;br /&gt;
Status: Done, known as delayed logging.&lt;br /&gt;
&lt;br /&gt;
Experimental in 2.6.35, stable for production in 2.6.37, planned for default&lt;br /&gt;
in 2.6.39.&lt;br /&gt;
&lt;br /&gt;
Design documentation can be found here:&lt;br /&gt;
&lt;br /&gt;
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/filesystems/xfs-delayed-logging-design.txt&lt;br /&gt;
&lt;br /&gt;
== Atomic Multi-Transaction Operations ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A feature asynchronous transaction aggregation makes possible is atomic&lt;br /&gt;
multi-transaction operations.  On the first transaction we hold the queue in&lt;br /&gt;
memory, preventing it from being committed. We can then do further transactions&lt;br /&gt;
that will end up in the same commit record, and on the final transaction we&lt;br /&gt;
unlock the async transaction queue. This will allow all those transaction to be&lt;br /&gt;
applied atomically. This is far simpler than any other method I&#039;ve been looking&lt;br /&gt;
at to do this.&lt;br /&gt;
&lt;br /&gt;
After a bit of reflection, I think this feature may be necessary for correct&lt;br /&gt;
implementation of existing logging techniques. The way we currently implement&lt;br /&gt;
rolling transactions (with permanent log reservations and rolling&lt;br /&gt;
dup/commit/re-reserve sequences) would seem to require all the commits in a&lt;br /&gt;
rolling transaction to be including in a single commit record.  If I understand&lt;br /&gt;
history and the original design correctly, these rolling transactions were&lt;br /&gt;
implemented so that large, complex transactions would not pin the tail of the&lt;br /&gt;
log as they progressed.  IOWs, they implicitly use re-logging to keep the tail&lt;br /&gt;
of the log moving forward as they progress and continue to modify items in the&lt;br /&gt;
transaction.&lt;br /&gt;
&lt;br /&gt;
Given we are using asynchronous transaction aggregation as a method of reducing&lt;br /&gt;
re-logging, it would make sense to prevent these sorts of transactions from&lt;br /&gt;
pinning the tail of the log at all. Further, because we are effectively&lt;br /&gt;
disturbing the concept of unique transactions, I don&#039;t think that allowing a&lt;br /&gt;
rolling transaction to span aggregated commits is valid as we are going to be&lt;br /&gt;
ignoring the transaction IDs that are used to identify individual transactions.&lt;br /&gt;
&lt;br /&gt;
Hence I think it is a good idea to simply replace rolling transactions with&lt;br /&gt;
atomic multi-transaction operations. This may also allow us to split some of&lt;br /&gt;
the large compound transactions into smaller, more self contained transactions.&lt;br /&gt;
This would reduce reservation pressure on log space in the common case where&lt;br /&gt;
all the corner cases in the transactions are not taken. In terms of&lt;br /&gt;
implementation, I think we can initially augment the permanent transaction&lt;br /&gt;
reservation/release interface to acheive this. With a working implementation,&lt;br /&gt;
we can then look to changing to a more explicit interface and slowly work to&lt;br /&gt;
remove the &#039;permanent log transaction&#039; concept entirely. This shold simplify&lt;br /&gt;
the log code somewhat....&lt;br /&gt;
&lt;br /&gt;
Note: This asynchronous transaction aggregation is originally based on a&lt;br /&gt;
concept floated by Nathan Scott called &#039;Delayed Logging&#039; after observing how&lt;br /&gt;
ext3 implemented journalling.  This never passed more than a concept&lt;br /&gt;
description phase....&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Operation Based Logging ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The second approach to reducing log traffic is to change exactly what we&lt;br /&gt;
log in the transactions. At the moment, what we log is the exact change to&lt;br /&gt;
the item that is being made. For things like inodes and dquots, this isn&#039;t&lt;br /&gt;
particularly expensive because it is already a very compact form. The issue&lt;br /&gt;
comes with changes that are logged in buffers.&lt;br /&gt;
&lt;br /&gt;
The prime example of this is a btree modification that involves either removing&lt;br /&gt;
or inserting a record into a buffer. The records are kept in compact form, so an&lt;br /&gt;
insert or remove will also move other records around in the buffer. In the worst&lt;br /&gt;
case, a single insert or remove of a 16 byte record can dirty an entire block&lt;br /&gt;
(4k generally, but could be up to 64k). In this case, if we were to log the&lt;br /&gt;
btree operation (e.g. insert {record, index}) rather than the resultant change&lt;br /&gt;
on the buffer the overhead of a btree operation is fixed. Such logging also&lt;br /&gt;
allows us to avoid needing to log the changes due to splits and merges - we just&lt;br /&gt;
replay the operation and subsequent splits/merges get done as part of replay.&lt;br /&gt;
&lt;br /&gt;
The result of this is that complex transactions no longer need as much log space&lt;br /&gt;
as all possible change they can cause - we only log the basic operations that&lt;br /&gt;
are occurring and their result. Hence transaction end up being much smaller,&lt;br /&gt;
vary less in size between empty and full filesystems, etc. An example set of&lt;br /&gt;
operations describing all the changes made by an extent allocation on an inode&lt;br /&gt;
would be:&lt;br /&gt;
&lt;br /&gt;
	- inode X intent to allocate extent {off, len}&lt;br /&gt;
	- AGCNT btree update record in AG X {old rec} {new rec values}&lt;br /&gt;
	- AGBNO btree delete record in AG X {block, len}&lt;br /&gt;
	- inode X BMBT btree insert record {off, block, len}&lt;br /&gt;
	- inode X delta&lt;br /&gt;
&lt;br /&gt;
This comes down to a relatively small, bound amount of space which is close the&lt;br /&gt;
minimun and existing allocation transaction would consume.  However, with this&lt;br /&gt;
method of logging the transaction size does not increase with the size of&lt;br /&gt;
structures or the amount of updates necessary to complete the operations.&lt;br /&gt;
&lt;br /&gt;
A major difference to the existing transaction system is that re-logging&lt;br /&gt;
of items doesn&#039;t fit very neatly with operation based logging. &lt;br /&gt;
&lt;br /&gt;
There are three main disadvantages to this approach:&lt;br /&gt;
&lt;br /&gt;
	- recovery becomes more complex - it will need to change substantially&lt;br /&gt;
	  to accomodate operation replay rather than just reading from disk&lt;br /&gt;
	  and applying deltas.&lt;br /&gt;
	- we have to create a whole new set of item types and add the necessary&lt;br /&gt;
	  hooks into the code to log all the operations correctly.&lt;br /&gt;
	- re-logging is probably not possible, and that introduces &lt;br /&gt;
	  differences to the way we&#039;ll need to track objects for flushing. It&lt;br /&gt;
	  may, in fact, require transaction IDs in all objects to allow us&lt;br /&gt;
	  to determine what the last transaction that modified the item&lt;br /&gt;
	  on disk was during recovery.&lt;br /&gt;
&lt;br /&gt;
Changing the logging strategy as described is a much more fundamental change to&lt;br /&gt;
XFS than asynchronous transaction aggregation. It will be difficult to change&lt;br /&gt;
to such a model in an evolutionary manner; it is more of a &#039;flag day&#039; style&lt;br /&gt;
change where then entire functionality needs to be added in one hit. Given that&lt;br /&gt;
we will also still have to support the old log format, it doesn&#039;t enable us to&lt;br /&gt;
remove any code, either.&lt;br /&gt;
&lt;br /&gt;
Given that we are likely to see major benefits in the problem workloads as a&lt;br /&gt;
result of asynchronous transaction aggregation, it may not be necessary to&lt;br /&gt;
completely rework the transaction subsystem. Combining aggregation with an&lt;br /&gt;
ongoing process of targeted reduction of transaction size will provide benefits&lt;br /&gt;
out to at least the medium term. It is unclear whether this direction will be&lt;br /&gt;
sufficient in the long run until we can measure the benefit that aggregation&lt;br /&gt;
will provide.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Reducing Transaction Overhead ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To switch tracks completely, I have not addressed general issues with overhead&lt;br /&gt;
in the transaction subsystem itself. There are several points where the&lt;br /&gt;
transaction subsystem will single thread because of filesystem scope locks and&lt;br /&gt;
structures.  We have, for example, the log grant lock for protecting&lt;br /&gt;
reservation and used log space, the AIL lock for tracking dirty metadata, the&lt;br /&gt;
log state lock for state transition of log buffers and other associated&lt;br /&gt;
structure modifications.&lt;br /&gt;
&lt;br /&gt;
We have already started down the path of reducing contention in&lt;br /&gt;
various paths. For example:&lt;br /&gt;
&lt;br /&gt;
	- changing iclog reference counts to atomics to avoid needing the log&lt;br /&gt;
	  state lock on every transaction commit&lt;br /&gt;
	- protecting iclog callback lists with a per-iclog lock instead of the log&lt;br /&gt;
	  state lock&lt;br /&gt;
	- removing the AIL lock from the transaction reserve path by isolating&lt;br /&gt;
	  AIL tail pushing to a single thread instead of being done&lt;br /&gt;
	  synchronously.&lt;br /&gt;
&lt;br /&gt;
Asynchronous transaction aggregation is likely to perturb the current known&lt;br /&gt;
behaviour and bottlenecks as a result of moving all of the log interfacing out&lt;br /&gt;
of the direct transaction commit path.  Similar to moving the AIL pushing into&lt;br /&gt;
it&#039;s own thread, this will mean that there will typically only be a single&lt;br /&gt;
thread formatting and writing to iclog buffers. This will remove much of the&lt;br /&gt;
parallelism that puts excessive pressure on many of these locks.&lt;br /&gt;
&lt;br /&gt;
I am certain that asynchronous transaction aggregation will open up new areas&lt;br /&gt;
of optimisation in the log formatting and dispatch code - it will probably&lt;br /&gt;
enable us to remove a lot of the complexity because we will be able to directly&lt;br /&gt;
control the parallelism in the formatting and dispatch of log buffers. This&lt;br /&gt;
implies that we may not need to be limited to a fixed pool of fixed sized log&lt;br /&gt;
buffers for writing transactions to disk.&lt;br /&gt;
&lt;br /&gt;
However, it is probably best to leave consideration of such optimisations until&lt;br /&gt;
after the asynchronous transaction aggregation is implemented and we can&lt;br /&gt;
directly observe the pain points that become apparent as a result of such a&lt;br /&gt;
change.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Reducing Recovery Time ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With 2GB logs, recovery can take an awfully long time due to the need&lt;br /&gt;
to read each object synchronously as we process the journal. An obvious&lt;br /&gt;
way to avoid this is to add another pass to the processing to do asynchronous&lt;br /&gt;
readahead of all the objects in the log before doing the processing passes.&lt;br /&gt;
This will populate the cache as quickly as possible and hide any read latency&lt;br /&gt;
that could occur as we process commit records.&lt;br /&gt;
&lt;br /&gt;
A logical extension to this is to sort the objects in ascending offset order&lt;br /&gt;
before issuing I/O on them. That will further optimise the readahead I/O&lt;br /&gt;
to reduce seeking and hence should speed up the read phase of recovery&lt;br /&gt;
further.&lt;br /&gt;
&lt;br /&gt;
== ToDo ==&lt;br /&gt;
Further investigation of recovery for future optimisation.&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=Improving_inode_Caching&amp;diff=2135</id>
		<title>Improving inode Caching</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=Improving_inode_Caching&amp;diff=2135"/>
		<updated>2010-12-23T03:51:48Z</updated>

		<summary type="html">&lt;p&gt;Dgc: /* Compressed Inode Cache */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Future Directions for XFS&lt;br /&gt;
&lt;br /&gt;
== Improving Inode Caching and Operation in XFS ==&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Thousand foot view:&lt;br /&gt;
&lt;br /&gt;
We want to drive inode lookup in a manner that is as parallel, scalable and low&lt;br /&gt;
overhead as possible. This means efficient indexing, lowering memory&lt;br /&gt;
consumption, simplifying the caching heirachy, removing duplication and&lt;br /&gt;
reducing/removing lock traffic.&lt;br /&gt;
&lt;br /&gt;
In addition, we want to provide a good foundation for simplifying inode I/O,&lt;br /&gt;
improving writeback clustering, preventing RMW of inode buffers under memory&lt;br /&gt;
pressure, reducing creation and deletion overhead and removing writeback of&lt;br /&gt;
unlogged changes completely.&lt;br /&gt;
&lt;br /&gt;
There are a variety of features in disconnected trees and patch sets that need&lt;br /&gt;
to be combined to acheive this - the basic structure needed to implement this is&lt;br /&gt;
already in mainline and that is the radix tree inode indexing.  Further&lt;br /&gt;
improvements are going to be based around this structure and using it&lt;br /&gt;
effectively to avoid needing other indexing mechanisms.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Discussion:&lt;br /&gt;
&lt;br /&gt;
== Combining XFS and VFS inodes ==&lt;br /&gt;
&lt;br /&gt;
Status: Done (October 2008)&lt;br /&gt;
&lt;br /&gt;
== Compressed Inode Cache ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The XFs inode cache uses a lot of memory. We can avoid this problem by making&lt;br /&gt;
use of the compressed inode cache - only the active inodes are held in a&lt;br /&gt;
non-compressed form, hence most inodes will end up being cached in compressed&lt;br /&gt;
form rather than in the XFS/linux inode form.  The compressed form can reduce&lt;br /&gt;
the cached inode footprint to 200-300 bytes per inode instead of 1-1.1k that&lt;br /&gt;
they currently take on a 64bit system. Hence by moving to a compressed cache we&lt;br /&gt;
can greatly increase the number of inodes cached in a given amount of memory&lt;br /&gt;
which more that offsets any comparitive increase we will see from inodes in&lt;br /&gt;
reclaim. the compressed cache should really have a LRU and a shrinker as well&lt;br /&gt;
so that memory pressure will slowly trim it as memory demands occur. [Note:&lt;br /&gt;
this compressed cache is discussed further later on in the reclaim context.]&lt;br /&gt;
&lt;br /&gt;
== Fixed Inode Cache Size ==&lt;br /&gt;
&lt;br /&gt;
It is worth noting that for embedded systems and appliances it may be worth while allowing&lt;br /&gt;
the size of the caches to be fixed. Also, to prevent memory fragmentation&lt;br /&gt;
problems, we could simply allocate that memory to the compressed cache slab.&lt;br /&gt;
In effect, this would become a &#039;static slab&#039; in that it has a bound maximum&lt;br /&gt;
size and never frees and memory. When the cache is full, we reclaim an&lt;br /&gt;
object out of it for reuse - this could be done by triggering the shrinker&lt;br /&gt;
to reclaim from the LRU. This would prevent the compressed inode cache from&lt;br /&gt;
consuming excessive amounts of memory in tightly constrained evironments.&lt;br /&gt;
Such an extension to the slab caches does not look difficult to implement,&lt;br /&gt;
and would allow such customisation with minimal deviation from mainline code.&lt;br /&gt;
&lt;br /&gt;
== Bypassing the Linux Inode Cache ==&lt;br /&gt;
&lt;br /&gt;
Lookups: Done (October 2008)&lt;br /&gt;
&lt;br /&gt;
Tracking dirty inodes: Done&lt;br /&gt;
&lt;br /&gt;
Writeback of dirty inodes: Done&lt;br /&gt;
&lt;br /&gt;
Writeback of dirty pages: still executed the by VFS&lt;br /&gt;
&lt;br /&gt;
Now that we can track dirty inodes ourselves, we can pretty much isolate&lt;br /&gt;
writeback of both data and inodes from the generic pdflush code. If we add a&lt;br /&gt;
hook high up in the pdflush path that simply passes us a writeback control&lt;br /&gt;
structure with the current writeback guidelines, we can do writeback within&lt;br /&gt;
those guidelines in the most optimal fashion for XFS.&lt;br /&gt;
&lt;br /&gt;
== Avoiding the Generic pdflush Code ==&lt;br /&gt;
&lt;br /&gt;
Writeback of inodes via AIL: Done&lt;br /&gt;
&lt;br /&gt;
For pdflush driven writeback, we only want to write back data; all other inode&lt;br /&gt;
writeback should be driven from the AIL (our time ordered dirty metadata list)&lt;br /&gt;
or xfssyncd in a manner that is most optimal for XFS.&lt;br /&gt;
&lt;br /&gt;
Furthermore, if we implement our own pdflush method, we can parallelise it in&lt;br /&gt;
several ways. We can ensure that each filesystem has it&#039;s own flush thread or&lt;br /&gt;
thread pool, we can have a thread pool shared by all filesystems (like pdflush&lt;br /&gt;
currently operates), we can have a flush thread per inode radix tree, and so&lt;br /&gt;
one. The method of paralleisation is open for interpretation, but enabling&lt;br /&gt;
multiple flush threads to operate on a single filesystem is one of the necessary&lt;br /&gt;
requirements to avoid data writeback (and hence delayed allocation) being&lt;br /&gt;
limited to the throughput of a single CPU per filesystem.&lt;br /&gt;
&lt;br /&gt;
== Improving Inode Writeback == &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To optimise inode writeback, we really need to reduce the impact of inode&lt;br /&gt;
buffer read-modify-write cycles. XFS is capable of caching far more inodes in&lt;br /&gt;
memory than it has buffer space available for, so RMW cycles during inode&lt;br /&gt;
writeback under memory pressure are quite common. Firstly, we want to avoid&lt;br /&gt;
blocking pdflush at all costs.  Secondly, we want to issue as much localised&lt;br /&gt;
readahead as possible in ascending offset order to allow both elevator merging&lt;br /&gt;
of readahead and as little seeking as possible. Finally, we want to issue all&lt;br /&gt;
the write cycles as close together as possible to allow the same elevator and&lt;br /&gt;
I/O optimisations to take place.&lt;br /&gt;
&lt;br /&gt;
To do this, firstly we need the non-blocking inode flush semantics to issue&lt;br /&gt;
readahead on buffers that are not up-to-date rather than reading them&lt;br /&gt;
synchronously. Inode writeback already has the interface to handle inodes that&lt;br /&gt;
weren&#039;t flushed - we return EAGAIN from xfs_iflush() and the higher inode&lt;br /&gt;
writeback layers handle this appropriately. It would be easy to add another&lt;br /&gt;
flag to pass down to the buffer layer to say &#039;issue but don&#039;t wait for any&lt;br /&gt;
read&#039;. If we use a radix tree traversal to issue readahead in such a manner,&lt;br /&gt;
we&#039;ll get ascending offset readahead being issued.&lt;br /&gt;
&lt;br /&gt;
One problem with this is that we can issue too much readahead and thrash the&lt;br /&gt;
cache. A possible solution to this is to make the readahead a &#039;delayed read&#039;&lt;br /&gt;
and on I/o completion add it to a queue that holds a reference on the buffer.&lt;br /&gt;
If a followup read occurs soon after, we remove it from the queue and drop that&lt;br /&gt;
reference. This prevents the buffer from being reclaimed in betwen the&lt;br /&gt;
readahead completing and the real read being issued. We should also issue this&lt;br /&gt;
delayed read on buffers that are in the cache so that they don&#039;t get reclaimed&lt;br /&gt;
to make room for the readahead.&lt;br /&gt;
&lt;br /&gt;
To prevent buildup of delayed read buffers, we can periodically purge them -&lt;br /&gt;
those that are older than a given age (say 5 seconds) can be removed from the&lt;br /&gt;
list and their reference dropped. This will free the buffer and allow it&#039;s&lt;br /&gt;
pages to be reclaimed.&lt;br /&gt;
&lt;br /&gt;
Once we have done the readahead pass, we can then do a modify and writeback&lt;br /&gt;
pass over all the inodes, knowing that there will be no read cycles to delay&lt;br /&gt;
this step. Once again, a radix tree traversal gives us ascending order&lt;br /&gt;
writeback and hence the modified buffers we send to the device will be in&lt;br /&gt;
optimal order for merging and minimal seek overhead.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Contiguous Inode Allocation ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To make optimal use of the radix tree cache and enable wide-scale clustering of&lt;br /&gt;
inode writeback across multiple clusters, we really need to ensure that inode&lt;br /&gt;
allocation occurs in large contiguous chunks on disk. Right now we only&lt;br /&gt;
allocate chunks of 64 inodes at a time; ideally we want to allocate a stripe&lt;br /&gt;
unit (or multiple of) full of inodes at a time. This would allow inode&lt;br /&gt;
writeback clustering to do full stripe writes to the underlying RAID if there&lt;br /&gt;
are dirty inodes spanning the entire stripe unit.&lt;br /&gt;
&lt;br /&gt;
The problem with doing this is that we don&#039;t want to introduce the latency of&lt;br /&gt;
creating megabytes of inodes when only one is needed for the current operation.&lt;br /&gt;
Hence we need to push the inode creation into a background thread and use that&lt;br /&gt;
to create contiguous inode chunks asynchronously. This moves the actual on-disk&lt;br /&gt;
allocation of inodes out of the normal create path; it should always be able to&lt;br /&gt;
find a free inode without doing on disk allocation. This will simplify the&lt;br /&gt;
create path by removing the allocate-on-disk-then-retry-the-create double&lt;br /&gt;
transaction that currently occurs.&lt;br /&gt;
&lt;br /&gt;
As an aside, we could preallocate a small amount of inodes in each AG (10-20MB&lt;br /&gt;
of inodes per AG?) without impacting mkfs time too greatly. This would allow&lt;br /&gt;
the filesystem to be used immediately on the first mount without triggering&lt;br /&gt;
lots of background allocation. This could alsobe done after the first mount&lt;br /&gt;
occurs, but that could interfere with typical benchmarking situations. Another&lt;br /&gt;
good reason for this preallocation is that it will help reduce xfs_repair&lt;br /&gt;
runtime for most common filesystem usages.&lt;br /&gt;
&lt;br /&gt;
One of the issues that the background create will cause is a substantial amount&lt;br /&gt;
of log traffic - every inode buffer initialised will be logged in whole. Hence&lt;br /&gt;
if we create a megabyte of inodes, we&#039;ll be causing a megabyte of log traffic&lt;br /&gt;
just for the inode buffers we&#039;ve initialised.  This is relatively simple to fix&lt;br /&gt;
- we don&#039;t log the buffer, we just log the fact that we need to initialise&lt;br /&gt;
inodes in a given range.  In recovery, when we see this transaction, then we&lt;br /&gt;
build the buffers, initialise them and write them out. Hence, we don&#039;t need to&lt;br /&gt;
log the buffers used to initialise the inodes.&lt;br /&gt;
&lt;br /&gt;
Also, we can use the background allocations to keep track of recently allocated&lt;br /&gt;
inode regions in the per-ag. Using that information to select the next inode to&lt;br /&gt;
be used rather than requiring btree searches on every create will greatly reduce&lt;br /&gt;
the CPU overhead of workloads that create lots of new inodes. It is not clear&lt;br /&gt;
whether a single background thread will be able to allocate enough inodes&lt;br /&gt;
to keep up with demand from the rest of the system - we may need multiple&lt;br /&gt;
threads for large configurations.&lt;br /&gt;
&lt;br /&gt;
== Single Block Inode Allocation ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
One of the big problems we have withe filesystems that are approaching&lt;br /&gt;
full is that it can be hard to find a large enough extent to hold 64 inodes.&lt;br /&gt;
We&#039;ve had ENOSPC errors on inode allocation reported on filesystems that&lt;br /&gt;
are only 85% full. This is a sign of free space fragmentation, and it&lt;br /&gt;
prevents inode allocation from succeeding. We could (and should) write&lt;br /&gt;
a free space defragmenter, but that does not solve the problem - it&#039;s&lt;br /&gt;
reactive, not preventative.&lt;br /&gt;
&lt;br /&gt;
The main problem we have is that XFS uses inode chunk size and alignment&lt;br /&gt;
to optimise inode number to disk location conversion. That is, the conversion&lt;br /&gt;
becomes a single set of shifts and masks instead of an AGI btree lookup.&lt;br /&gt;
This optimisation substantially reduces the CPU and I/O overhead of&lt;br /&gt;
inode lookups, but it does limit our flexibility. If we break the&lt;br /&gt;
alignment restriction, every lookup has to go back to a btree search.&lt;br /&gt;
Hence we really want to avoid breaking chunk alignment and size&lt;br /&gt;
rules.&lt;br /&gt;
&lt;br /&gt;
An approach to avoiding violation of this rule is to be able to determine which&lt;br /&gt;
index to look up when parsing the inode number. For example, we could use the&lt;br /&gt;
high bit of the inode number to indicate that it is located in a non-aligned&lt;br /&gt;
inode chunk and hence needs to be looked up in the btree. This would avoid&lt;br /&gt;
the lookup penalty for correctly aligned inode chunks.&lt;br /&gt;
&lt;br /&gt;
If we then redefine the meaning of the contents of the AGI btree record for&lt;br /&gt;
such inode chunks, we do not need a new index to keep these in. Effectively,&lt;br /&gt;
we need to add a bitmask to the record to indicate which blocks inside&lt;br /&gt;
the chunk can actually contain inodes. We still use aligned/sized records,&lt;br /&gt;
but mask out the sections that we are not allowed to allocate inodes in.&lt;br /&gt;
Effectively, this would allow sparse inode chunks. There may be limitations&lt;br /&gt;
on the resolution of sparseness depending on inode size and block size,&lt;br /&gt;
but for the common cases of 4k block size and 256 or 512 byte inodes I&lt;br /&gt;
think we can run a fully sparse mapping for each inode chunk.&lt;br /&gt;
&lt;br /&gt;
This would allow us to allocate inode extents of any alignment and size&lt;br /&gt;
that fits *inside* the existing alignment/size limitations. That is,&lt;br /&gt;
a single extent allocation could not span two btree records, but can&lt;br /&gt;
lie anywhere inside a single record. It also means that we can do&lt;br /&gt;
multiple extent allocations within one btree record to make optimal&lt;br /&gt;
use of the fragmented free space.&lt;br /&gt;
&lt;br /&gt;
It should be noted that this will probably have impact on some of the&lt;br /&gt;
inode cluster buffer mapping and clustering algorithms. It is not clear&lt;br /&gt;
exactly what impact yet, but certainly write clustering will be affected.&lt;br /&gt;
Fortunately we&#039;ll be able to detect the inodes that will have this problem&lt;br /&gt;
by the high bit in the inode number.&lt;br /&gt;
&lt;br /&gt;
== Inode Unlink ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If we turn to look at unlink and reclaim interactions, there are a few&lt;br /&gt;
optimisations that can be made.  Firstly, we don&#039;t need to do inode inactivation&lt;br /&gt;
in reclaim threads - these transactions can easily be pushed to a background&lt;br /&gt;
thread. This means that xfs_inactive would be little more than a vmtruncate()&lt;br /&gt;
call and queuing to a workqueue. This will substantially speed up the processing&lt;br /&gt;
of prune_icache() - we&#039;ll get inodes moved into reclaim much faster than we do&lt;br /&gt;
right now.&lt;br /&gt;
&lt;br /&gt;
This will have a noticable effect, though. When inodes are unlinked the space&lt;br /&gt;
consumed by those inodes may not be immediately freed - it will be returned as&lt;br /&gt;
the inodes are processed through the reclaim threads. This means that userspace&lt;br /&gt;
monitoring tools such as &#039;df&#039; may not immediately reflect the result of a&lt;br /&gt;
completed unlink operation. This will be a user visible change in behaviour,&lt;br /&gt;
though in most cases should not affect anyone and for those that it does affect&lt;br /&gt;
a &#039;sync&#039; should be sufficient to wait for the space to be returned.&lt;br /&gt;
&lt;br /&gt;
Now that inodes to be unlinked are out of general circulation, we can make the&lt;br /&gt;
unlinked path more complex. It is desirable to move the unlinked list from the&lt;br /&gt;
inode buffer to the inode core, but that has locking implications for incore&lt;br /&gt;
unlinked. Hence we really need background thread processing to enable this to&lt;br /&gt;
work (i.e. being able to requeue inodes for later processing). To ensure that&lt;br /&gt;
to overhead of this work is not a limiting factor, we will probably need&lt;br /&gt;
multiple workqueue processing threads for this.&lt;br /&gt;
&lt;br /&gt;
Moving the logging to the inode core enables two things - it allows us to keep&lt;br /&gt;
an in-memory copy of the unlinked list off the perag and that allows us to remove&lt;br /&gt;
xfs_inotobp(). The in-memory unlinked list means we don&#039;t have to read and&lt;br /&gt;
traverse the buffers every time we need to find the previous buffer to remove an&lt;br /&gt;
inode from the list, but it does mean we have to take the inode lock. If the&lt;br /&gt;
previous inode is locked, then we can&#039;t remove the inode from the unlinked list&lt;br /&gt;
so we must requeue it for this to occur at a later time.&lt;br /&gt;
&lt;br /&gt;
Combined with the changes to inode create, we effectively will only use the&lt;br /&gt;
inode buffer in the transaction subsystem for marking the region stale when&lt;br /&gt;
freeing an inode chunk from disk (i.e. the default noikeep configuration). If&lt;br /&gt;
we are using large inode allocation, we don&#039;t want to be freeing random inode&lt;br /&gt;
chunks - this will just leave us with fragmented inode regions and undo all the&lt;br /&gt;
good work that was done originally.&lt;br /&gt;
&lt;br /&gt;
To avoid this, we should not be freeing inode chunks as soon as they no longer&lt;br /&gt;
have any empty inodes in them. We should periodically scan the AGI btree&lt;br /&gt;
looking for contiguous chunks that have no inodes allocated in them, and then&lt;br /&gt;
freeing the large contiguous regions we find in one go. It is likely this can&lt;br /&gt;
be done in a single transaction; it&#039;s one extent to be freed, along with a&lt;br /&gt;
contiguous set of records to be removed from the AGI btree so should not&lt;br /&gt;
require logging much at all. Also, the background scanning could be triggered&lt;br /&gt;
by a number of different events - low space in an AG, a large number of free&lt;br /&gt;
inodes in an AG, etc - as it doesn&#039;t need to be done frequently. As a result&lt;br /&gt;
of the lack of frequency that this needs to be done, it can probably be&lt;br /&gt;
handled by a single thread or delayed workqueue.&lt;br /&gt;
&lt;br /&gt;
Further optimisations are possible here - if we rule that the AGI btree is the&lt;br /&gt;
sole place that inodes are marked free or in-use (with the exception of&lt;br /&gt;
unlinked inodes attached to the AGI lists), then we can avoid the need to&lt;br /&gt;
write back unlinked inodes or read newly created inodes from disk.  This would&lt;br /&gt;
require all inodes to effectively use a random generation number assigned at&lt;br /&gt;
create time as we would not be reading it from disk - writing/reading the current&lt;br /&gt;
generation number appears to be the only real reason for doing this I/O. This&lt;br /&gt;
would require extra checks to determine if an inode is unlinked - we&lt;br /&gt;
need to do an imap lookup rather than reading it and then checking it is&lt;br /&gt;
valid if it is not already in memory. Avoiding the I/O, however, will greatly speed&lt;br /&gt;
up create and remove workloads. Note: the impact of this on the bulkstat algorithm&lt;br /&gt;
has not been determined yet.&lt;br /&gt;
&lt;br /&gt;
One of the issues we need to consider with this background inactivation is that&lt;br /&gt;
we will be able to defer a large quantity of inactivation transactions so we are&lt;br /&gt;
going to need to be careful about how much we allow to be queued. Simple queue&lt;br /&gt;
depth throttling should be all that is needed to keep this under control.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Reclaim Optimizations ==&lt;br /&gt;
&lt;br /&gt;
Tracking inodes for reclaim in radix tree: Done&lt;br /&gt;
&lt;br /&gt;
Using RCU for radix tree reclaim walks: Done&lt;br /&gt;
&lt;br /&gt;
Non-blocking background reclaim: Done&lt;br /&gt;
&lt;br /&gt;
Parallelised shrinker based reclaim: Done&lt;br /&gt;
&lt;br /&gt;
Now that we have efficient unlink, we&#039;ve got to handle the reclaim of all the&lt;br /&gt;
inodes that are now dead or simply not referenced. For inodes that are dirty,&lt;br /&gt;
we need to write them out to clean them. For inodes that are clean and not&lt;br /&gt;
unlinked, we need to compress them down for more compact storage. This involves&lt;br /&gt;
some CPU overhead, but it is worth noting that reclaiming of clean inodes&lt;br /&gt;
typically only occurs when we are under memory pressure.&lt;br /&gt;
&lt;br /&gt;
By compressing the XFS inode in this case, we are effectively reducing the&lt;br /&gt;
memory usage of the inode rather than freeing it directly. If we then get&lt;br /&gt;
another operation on that inode (e.g. the working set is slightly larger than&lt;br /&gt;
can be held in linux+XFS inode pairs, we avoid having to read the inode off&lt;br /&gt;
disk again - it simply gets uncompressed out of the cache. In essence we use&lt;br /&gt;
the compressed inode cache as an exclusive second level cache - it has higher&lt;br /&gt;
density than the primary cache and higher load latency and CPU overhead,&lt;br /&gt;
but it still avoids I/O in exactly the same manner as the primary cache.&lt;br /&gt;
&lt;br /&gt;
We cannot allow unrestricted build-up of reclaimable inodes - the memory they&lt;br /&gt;
consume will be large, so we should be aiming to compress reclaimable inodes as&lt;br /&gt;
soon as they are clean.  This will prevent buildup of memory consuming&lt;br /&gt;
uncompressed inodes that are not likely to be referenced again immediately.&lt;br /&gt;
&lt;br /&gt;
This clean inode reclaimation process can be accelerated by triggering reclaim&lt;br /&gt;
on inode I/O completion. If the inode is clean and reclaimable we should&lt;br /&gt;
trigger immediate reclaim processing of that inode.  This will mean that&lt;br /&gt;
reclaim of newly cleaned inodes will not get held up behind reclaim of dirty&lt;br /&gt;
inodes.&lt;br /&gt;
&lt;br /&gt;
For inodes that are unlinked, we can simply free them in reclaim as theƦ&lt;br /&gt;
are no longer in use. We don&#039;t want to poison the compressed cache with&lt;br /&gt;
unlinked inodes, nor do we need to because we can allocate new inodes&lt;br /&gt;
without incurring I/O.&lt;br /&gt;
&lt;br /&gt;
Still, we may end up with lots of inodes queued for reclaim. We may need&lt;br /&gt;
to implement a throttle mechanism to slow down the rate at which inodes&lt;br /&gt;
are queued for reclaimation in the situation where the reclaim process&lt;br /&gt;
is not able to keep up. It should be noted that if we parallelise inode&lt;br /&gt;
writeback we should also be able to parallelise inode reclaim via&lt;br /&gt;
the same mechanism, so the need for throttling may relatively low&lt;br /&gt;
if we can have multiple inodes under reclaim at once.&lt;br /&gt;
&lt;br /&gt;
It should be noted that complexity is exposed by interactions with concurrent&lt;br /&gt;
lookups, especially if we move to RCU locking on the radix tree. Firstly, we&lt;br /&gt;
need to be able to do an atomic swap of the compressed inode for the&lt;br /&gt;
uncompressed inode in the radix tree (and vice versa), to be able to tell them&lt;br /&gt;
apart (magic #), and to have atomic reference counts to ensure we can avoid use&lt;br /&gt;
after free situations when lookups race with compression or freeing.&lt;br /&gt;
&lt;br /&gt;
Secondly, with the complex unlink/reclaim interactions we will need to be&lt;br /&gt;
careful to detect inodes in the process of reclaim - the lookupp process&lt;br /&gt;
will need to do different things depending on the state of reclaim. Indeed,&lt;br /&gt;
we will need to be able to cancel reclaim of an unlinked inode if we try&lt;br /&gt;
to allocate it before it has been fully unlinked or reclaimed. The same&lt;br /&gt;
can be said for an inode in the process of being compressed - if we get&lt;br /&gt;
a lookup during the compression process, we want to return the existing&lt;br /&gt;
inode, not have to wait, re-allocate and uncompress it again. These&lt;br /&gt;
are all solvable issues - they just add complexity.&lt;br /&gt;
&lt;br /&gt;
== Accelerated Reclaim of buftarg Page Cache for Inodes ==&lt;br /&gt;
----------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Per-buftarg buffer LRU reclaim: Done&lt;br /&gt;
&lt;br /&gt;
Per-buftarg shrinker: Done&lt;br /&gt;
&lt;br /&gt;
Per-buffer type reclaim prioritisation: Done&lt;br /&gt;
&lt;br /&gt;
For single use inodes or even read-only inodes, we read them in, use them, then&lt;br /&gt;
reclaim them. With the compressed cache, they&#039;ll get compressed and live a lot&lt;br /&gt;
longer in memory. However, we also will have the inode cluster buffer pages&lt;br /&gt;
sitting in memory for some length of time after the inode was read in. This can&lt;br /&gt;
consume a large amount of memory that will never be used again, and does not&lt;br /&gt;
get reclaimed until they are purged from the LRU by the VM.  It would be&lt;br /&gt;
advantageous to accelerate the reclaim of these pages so that they do not build&lt;br /&gt;
up unneccessarily.&lt;br /&gt;
&lt;br /&gt;
A better method would appear to be to leverage the delayed read queue&lt;br /&gt;
mechanism. This delayed read queue pins read buffers for a short period of&lt;br /&gt;
time, and then if they have not been referenced they get torn down.  If, as&lt;br /&gt;
part of this delayed read buffer teardown procedure we all free the backing&lt;br /&gt;
pages completely, we acheive the exact same result as having our own LRUs to&lt;br /&gt;
manage the page cache. This seems much simpler and a much more holistic&lt;br /&gt;
approach to solving the problem than implementing page LRUs.&lt;br /&gt;
&lt;br /&gt;
== Killing Bufferheads (a.k.a &amp;quot;Die, buggerheads, Die!&amp;quot;) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[This is not strictly about inode caching, but doesn&#039;t fit into&lt;br /&gt;
other areas of development as closely as it does to inode caching&lt;br /&gt;
optimisations.]&lt;br /&gt;
&lt;br /&gt;
XFS is extent based. The Linux page cache is block based. Hence for&lt;br /&gt;
every cached page in memory, we have to attach a structure for mapping&lt;br /&gt;
the blocks on that page back to to the on-disk location. In XFs, we also&lt;br /&gt;
use this to hold state for delayed allocation and unwritten extent blocks&lt;br /&gt;
so the generic code can do the right thing when necessary. We also&lt;br /&gt;
use it to avoid extent lookups at various times within the XFS I/O&lt;br /&gt;
path.&lt;br /&gt;
&lt;br /&gt;
However, this has a massive cost. While XFS might represent the&lt;br /&gt;
disk mapping of a 1GB extent in 24 bytes of memory, the page cache&lt;br /&gt;
requires 262,144 bufferheads (assuming 4k block size) to represent the&lt;br /&gt;
same mapping. That&#039;s roughly 14MB of memory neededtoo represent that.&lt;br /&gt;
&lt;br /&gt;
Chris Mason wrote an extent map representation for page cache state&lt;br /&gt;
and mappings for BTRFS; that code is mostly generic and could be&lt;br /&gt;
adapted to XFS. This would allow us to hold all the page cache state&lt;br /&gt;
in extent format and greatly reduce the memory overhead that it currently&lt;br /&gt;
has. The tradeoff is increased CPU overhead due to tree lookups where&lt;br /&gt;
structure lookups currently are used. Still, this has much lower&lt;br /&gt;
overhead than xfs_bmapi() based lookups, so the penalty is going to&lt;br /&gt;
be lower than if we did these lookups right now.&lt;br /&gt;
&lt;br /&gt;
If we make this change, we would then have three levels of extent&lt;br /&gt;
caching:&lt;br /&gt;
&lt;br /&gt;
	- the BMBT buffers&lt;br /&gt;
	- the XFS incore inode extent tree (iext*)&lt;br /&gt;
	- the page cache extent map tree&lt;br /&gt;
&lt;br /&gt;
Effectively, the XFS incore inode extent tree becomes redundant - all&lt;br /&gt;
the extent state it holds can be moved to the generic page cache tree&lt;br /&gt;
and we can do all our incore operations there. Our logging of changes&lt;br /&gt;
is based on the BMBT buffers, so getting rid of the iext layer would&lt;br /&gt;
not impact the transaction subsystem at all.&lt;br /&gt;
&lt;br /&gt;
Such integration with the generic code will also allow development&lt;br /&gt;
of generic writeback routines for delayed allocation, unwritten&lt;br /&gt;
extents, etc that are not specific to a given filesystem.&lt;br /&gt;
&lt;br /&gt;
== Demand Paging of Large Inode Extent Maps ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Currently the inode extent map is pinned  in memory until the inode is&lt;br /&gt;
reclaimed. Hence an inode with millions of extents will pin a large&lt;br /&gt;
amount of memory and this can cause serious issues in low memory&lt;br /&gt;
situations. Ideally we would like to be able to page the extent&lt;br /&gt;
map in and out once they get to a certain size to avoid this&lt;br /&gt;
problem. This feature requires more investigation before an overall&lt;br /&gt;
approach can be detailed here.&lt;br /&gt;
&lt;br /&gt;
It should be noted that if we move to an extent-based page cache mapping&lt;br /&gt;
tree, the associated extent state tree can be used to track sparse&lt;br /&gt;
regions. That is, regions of the extent map that are not in memory&lt;br /&gt;
can be easily represented and acceesses to an unread region can then&lt;br /&gt;
be used to trigger demand loading.&lt;br /&gt;
&lt;br /&gt;
== Food For Thought (Crazy Ideas) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If we are not using inode buffers for logging changes to inodes, we should&lt;br /&gt;
consider whether we need them at all. What benefit do the buffers bring us when&lt;br /&gt;
all we will use them for is read or write I/O?  Would it be better to go&lt;br /&gt;
straight to the buftarg page cache and do page based I/O via submit_bio()?&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=Improving_inode_Caching&amp;diff=2134</id>
		<title>Improving inode Caching</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=Improving_inode_Caching&amp;diff=2134"/>
		<updated>2010-12-23T03:51:34Z</updated>

		<summary type="html">&lt;p&gt;Dgc: /* Combining XFS and VFS inodes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Future Directions for XFS&lt;br /&gt;
&lt;br /&gt;
== Improving Inode Caching and Operation in XFS ==&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Thousand foot view:&lt;br /&gt;
&lt;br /&gt;
We want to drive inode lookup in a manner that is as parallel, scalable and low&lt;br /&gt;
overhead as possible. This means efficient indexing, lowering memory&lt;br /&gt;
consumption, simplifying the caching heirachy, removing duplication and&lt;br /&gt;
reducing/removing lock traffic.&lt;br /&gt;
&lt;br /&gt;
In addition, we want to provide a good foundation for simplifying inode I/O,&lt;br /&gt;
improving writeback clustering, preventing RMW of inode buffers under memory&lt;br /&gt;
pressure, reducing creation and deletion overhead and removing writeback of&lt;br /&gt;
unlogged changes completely.&lt;br /&gt;
&lt;br /&gt;
There are a variety of features in disconnected trees and patch sets that need&lt;br /&gt;
to be combined to acheive this - the basic structure needed to implement this is&lt;br /&gt;
already in mainline and that is the radix tree inode indexing.  Further&lt;br /&gt;
improvements are going to be based around this structure and using it&lt;br /&gt;
effectively to avoid needing other indexing mechanisms.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Discussion:&lt;br /&gt;
&lt;br /&gt;
== Combining XFS and VFS inodes ==&lt;br /&gt;
&lt;br /&gt;
Status: Done (October 2008)&lt;br /&gt;
&lt;br /&gt;
== Compressed Inode Cache ==&lt;br /&gt;
-----------------------------&lt;br /&gt;
&lt;br /&gt;
The XFs inode cache uses a lot of memory. We can avoid this problem by making&lt;br /&gt;
use of the compressed inode cache - only the active inodes are held in a&lt;br /&gt;
non-compressed form, hence most inodes will end up being cached in compressed&lt;br /&gt;
form rather than in the XFS/linux inode form.  The compressed form can reduce&lt;br /&gt;
the cached inode footprint to 200-300 bytes per inode instead of 1-1.1k that&lt;br /&gt;
they currently take on a 64bit system. Hence by moving to a compressed cache we&lt;br /&gt;
can greatly increase the number of inodes cached in a given amount of memory&lt;br /&gt;
which more that offsets any comparitive increase we will see from inodes in&lt;br /&gt;
reclaim. the compressed cache should really have a LRU and a shrinker as well&lt;br /&gt;
so that memory pressure will slowly trim it as memory demands occur. [Note:&lt;br /&gt;
this compressed cache is discussed further later on in the reclaim context.]&lt;br /&gt;
&lt;br /&gt;
== Fixed Inode Cache Size ==&lt;br /&gt;
&lt;br /&gt;
It is worth noting that for embedded systems and appliances it may be worth while allowing&lt;br /&gt;
the size of the caches to be fixed. Also, to prevent memory fragmentation&lt;br /&gt;
problems, we could simply allocate that memory to the compressed cache slab.&lt;br /&gt;
In effect, this would become a &#039;static slab&#039; in that it has a bound maximum&lt;br /&gt;
size and never frees and memory. When the cache is full, we reclaim an&lt;br /&gt;
object out of it for reuse - this could be done by triggering the shrinker&lt;br /&gt;
to reclaim from the LRU. This would prevent the compressed inode cache from&lt;br /&gt;
consuming excessive amounts of memory in tightly constrained evironments.&lt;br /&gt;
Such an extension to the slab caches does not look difficult to implement,&lt;br /&gt;
and would allow such customisation with minimal deviation from mainline code.&lt;br /&gt;
&lt;br /&gt;
== Bypassing the Linux Inode Cache ==&lt;br /&gt;
&lt;br /&gt;
Lookups: Done (October 2008)&lt;br /&gt;
&lt;br /&gt;
Tracking dirty inodes: Done&lt;br /&gt;
&lt;br /&gt;
Writeback of dirty inodes: Done&lt;br /&gt;
&lt;br /&gt;
Writeback of dirty pages: still executed the by VFS&lt;br /&gt;
&lt;br /&gt;
Now that we can track dirty inodes ourselves, we can pretty much isolate&lt;br /&gt;
writeback of both data and inodes from the generic pdflush code. If we add a&lt;br /&gt;
hook high up in the pdflush path that simply passes us a writeback control&lt;br /&gt;
structure with the current writeback guidelines, we can do writeback within&lt;br /&gt;
those guidelines in the most optimal fashion for XFS.&lt;br /&gt;
&lt;br /&gt;
== Avoiding the Generic pdflush Code ==&lt;br /&gt;
&lt;br /&gt;
Writeback of inodes via AIL: Done&lt;br /&gt;
&lt;br /&gt;
For pdflush driven writeback, we only want to write back data; all other inode&lt;br /&gt;
writeback should be driven from the AIL (our time ordered dirty metadata list)&lt;br /&gt;
or xfssyncd in a manner that is most optimal for XFS.&lt;br /&gt;
&lt;br /&gt;
Furthermore, if we implement our own pdflush method, we can parallelise it in&lt;br /&gt;
several ways. We can ensure that each filesystem has it&#039;s own flush thread or&lt;br /&gt;
thread pool, we can have a thread pool shared by all filesystems (like pdflush&lt;br /&gt;
currently operates), we can have a flush thread per inode radix tree, and so&lt;br /&gt;
one. The method of paralleisation is open for interpretation, but enabling&lt;br /&gt;
multiple flush threads to operate on a single filesystem is one of the necessary&lt;br /&gt;
requirements to avoid data writeback (and hence delayed allocation) being&lt;br /&gt;
limited to the throughput of a single CPU per filesystem.&lt;br /&gt;
&lt;br /&gt;
== Improving Inode Writeback == &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To optimise inode writeback, we really need to reduce the impact of inode&lt;br /&gt;
buffer read-modify-write cycles. XFS is capable of caching far more inodes in&lt;br /&gt;
memory than it has buffer space available for, so RMW cycles during inode&lt;br /&gt;
writeback under memory pressure are quite common. Firstly, we want to avoid&lt;br /&gt;
blocking pdflush at all costs.  Secondly, we want to issue as much localised&lt;br /&gt;
readahead as possible in ascending offset order to allow both elevator merging&lt;br /&gt;
of readahead and as little seeking as possible. Finally, we want to issue all&lt;br /&gt;
the write cycles as close together as possible to allow the same elevator and&lt;br /&gt;
I/O optimisations to take place.&lt;br /&gt;
&lt;br /&gt;
To do this, firstly we need the non-blocking inode flush semantics to issue&lt;br /&gt;
readahead on buffers that are not up-to-date rather than reading them&lt;br /&gt;
synchronously. Inode writeback already has the interface to handle inodes that&lt;br /&gt;
weren&#039;t flushed - we return EAGAIN from xfs_iflush() and the higher inode&lt;br /&gt;
writeback layers handle this appropriately. It would be easy to add another&lt;br /&gt;
flag to pass down to the buffer layer to say &#039;issue but don&#039;t wait for any&lt;br /&gt;
read&#039;. If we use a radix tree traversal to issue readahead in such a manner,&lt;br /&gt;
we&#039;ll get ascending offset readahead being issued.&lt;br /&gt;
&lt;br /&gt;
One problem with this is that we can issue too much readahead and thrash the&lt;br /&gt;
cache. A possible solution to this is to make the readahead a &#039;delayed read&#039;&lt;br /&gt;
and on I/o completion add it to a queue that holds a reference on the buffer.&lt;br /&gt;
If a followup read occurs soon after, we remove it from the queue and drop that&lt;br /&gt;
reference. This prevents the buffer from being reclaimed in betwen the&lt;br /&gt;
readahead completing and the real read being issued. We should also issue this&lt;br /&gt;
delayed read on buffers that are in the cache so that they don&#039;t get reclaimed&lt;br /&gt;
to make room for the readahead.&lt;br /&gt;
&lt;br /&gt;
To prevent buildup of delayed read buffers, we can periodically purge them -&lt;br /&gt;
those that are older than a given age (say 5 seconds) can be removed from the&lt;br /&gt;
list and their reference dropped. This will free the buffer and allow it&#039;s&lt;br /&gt;
pages to be reclaimed.&lt;br /&gt;
&lt;br /&gt;
Once we have done the readahead pass, we can then do a modify and writeback&lt;br /&gt;
pass over all the inodes, knowing that there will be no read cycles to delay&lt;br /&gt;
this step. Once again, a radix tree traversal gives us ascending order&lt;br /&gt;
writeback and hence the modified buffers we send to the device will be in&lt;br /&gt;
optimal order for merging and minimal seek overhead.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Contiguous Inode Allocation ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To make optimal use of the radix tree cache and enable wide-scale clustering of&lt;br /&gt;
inode writeback across multiple clusters, we really need to ensure that inode&lt;br /&gt;
allocation occurs in large contiguous chunks on disk. Right now we only&lt;br /&gt;
allocate chunks of 64 inodes at a time; ideally we want to allocate a stripe&lt;br /&gt;
unit (or multiple of) full of inodes at a time. This would allow inode&lt;br /&gt;
writeback clustering to do full stripe writes to the underlying RAID if there&lt;br /&gt;
are dirty inodes spanning the entire stripe unit.&lt;br /&gt;
&lt;br /&gt;
The problem with doing this is that we don&#039;t want to introduce the latency of&lt;br /&gt;
creating megabytes of inodes when only one is needed for the current operation.&lt;br /&gt;
Hence we need to push the inode creation into a background thread and use that&lt;br /&gt;
to create contiguous inode chunks asynchronously. This moves the actual on-disk&lt;br /&gt;
allocation of inodes out of the normal create path; it should always be able to&lt;br /&gt;
find a free inode without doing on disk allocation. This will simplify the&lt;br /&gt;
create path by removing the allocate-on-disk-then-retry-the-create double&lt;br /&gt;
transaction that currently occurs.&lt;br /&gt;
&lt;br /&gt;
As an aside, we could preallocate a small amount of inodes in each AG (10-20MB&lt;br /&gt;
of inodes per AG?) without impacting mkfs time too greatly. This would allow&lt;br /&gt;
the filesystem to be used immediately on the first mount without triggering&lt;br /&gt;
lots of background allocation. This could alsobe done after the first mount&lt;br /&gt;
occurs, but that could interfere with typical benchmarking situations. Another&lt;br /&gt;
good reason for this preallocation is that it will help reduce xfs_repair&lt;br /&gt;
runtime for most common filesystem usages.&lt;br /&gt;
&lt;br /&gt;
One of the issues that the background create will cause is a substantial amount&lt;br /&gt;
of log traffic - every inode buffer initialised will be logged in whole. Hence&lt;br /&gt;
if we create a megabyte of inodes, we&#039;ll be causing a megabyte of log traffic&lt;br /&gt;
just for the inode buffers we&#039;ve initialised.  This is relatively simple to fix&lt;br /&gt;
- we don&#039;t log the buffer, we just log the fact that we need to initialise&lt;br /&gt;
inodes in a given range.  In recovery, when we see this transaction, then we&lt;br /&gt;
build the buffers, initialise them and write them out. Hence, we don&#039;t need to&lt;br /&gt;
log the buffers used to initialise the inodes.&lt;br /&gt;
&lt;br /&gt;
Also, we can use the background allocations to keep track of recently allocated&lt;br /&gt;
inode regions in the per-ag. Using that information to select the next inode to&lt;br /&gt;
be used rather than requiring btree searches on every create will greatly reduce&lt;br /&gt;
the CPU overhead of workloads that create lots of new inodes. It is not clear&lt;br /&gt;
whether a single background thread will be able to allocate enough inodes&lt;br /&gt;
to keep up with demand from the rest of the system - we may need multiple&lt;br /&gt;
threads for large configurations.&lt;br /&gt;
&lt;br /&gt;
== Single Block Inode Allocation ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
One of the big problems we have withe filesystems that are approaching&lt;br /&gt;
full is that it can be hard to find a large enough extent to hold 64 inodes.&lt;br /&gt;
We&#039;ve had ENOSPC errors on inode allocation reported on filesystems that&lt;br /&gt;
are only 85% full. This is a sign of free space fragmentation, and it&lt;br /&gt;
prevents inode allocation from succeeding. We could (and should) write&lt;br /&gt;
a free space defragmenter, but that does not solve the problem - it&#039;s&lt;br /&gt;
reactive, not preventative.&lt;br /&gt;
&lt;br /&gt;
The main problem we have is that XFS uses inode chunk size and alignment&lt;br /&gt;
to optimise inode number to disk location conversion. That is, the conversion&lt;br /&gt;
becomes a single set of shifts and masks instead of an AGI btree lookup.&lt;br /&gt;
This optimisation substantially reduces the CPU and I/O overhead of&lt;br /&gt;
inode lookups, but it does limit our flexibility. If we break the&lt;br /&gt;
alignment restriction, every lookup has to go back to a btree search.&lt;br /&gt;
Hence we really want to avoid breaking chunk alignment and size&lt;br /&gt;
rules.&lt;br /&gt;
&lt;br /&gt;
An approach to avoiding violation of this rule is to be able to determine which&lt;br /&gt;
index to look up when parsing the inode number. For example, we could use the&lt;br /&gt;
high bit of the inode number to indicate that it is located in a non-aligned&lt;br /&gt;
inode chunk and hence needs to be looked up in the btree. This would avoid&lt;br /&gt;
the lookup penalty for correctly aligned inode chunks.&lt;br /&gt;
&lt;br /&gt;
If we then redefine the meaning of the contents of the AGI btree record for&lt;br /&gt;
such inode chunks, we do not need a new index to keep these in. Effectively,&lt;br /&gt;
we need to add a bitmask to the record to indicate which blocks inside&lt;br /&gt;
the chunk can actually contain inodes. We still use aligned/sized records,&lt;br /&gt;
but mask out the sections that we are not allowed to allocate inodes in.&lt;br /&gt;
Effectively, this would allow sparse inode chunks. There may be limitations&lt;br /&gt;
on the resolution of sparseness depending on inode size and block size,&lt;br /&gt;
but for the common cases of 4k block size and 256 or 512 byte inodes I&lt;br /&gt;
think we can run a fully sparse mapping for each inode chunk.&lt;br /&gt;
&lt;br /&gt;
This would allow us to allocate inode extents of any alignment and size&lt;br /&gt;
that fits *inside* the existing alignment/size limitations. That is,&lt;br /&gt;
a single extent allocation could not span two btree records, but can&lt;br /&gt;
lie anywhere inside a single record. It also means that we can do&lt;br /&gt;
multiple extent allocations within one btree record to make optimal&lt;br /&gt;
use of the fragmented free space.&lt;br /&gt;
&lt;br /&gt;
It should be noted that this will probably have impact on some of the&lt;br /&gt;
inode cluster buffer mapping and clustering algorithms. It is not clear&lt;br /&gt;
exactly what impact yet, but certainly write clustering will be affected.&lt;br /&gt;
Fortunately we&#039;ll be able to detect the inodes that will have this problem&lt;br /&gt;
by the high bit in the inode number.&lt;br /&gt;
&lt;br /&gt;
== Inode Unlink ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If we turn to look at unlink and reclaim interactions, there are a few&lt;br /&gt;
optimisations that can be made.  Firstly, we don&#039;t need to do inode inactivation&lt;br /&gt;
in reclaim threads - these transactions can easily be pushed to a background&lt;br /&gt;
thread. This means that xfs_inactive would be little more than a vmtruncate()&lt;br /&gt;
call and queuing to a workqueue. This will substantially speed up the processing&lt;br /&gt;
of prune_icache() - we&#039;ll get inodes moved into reclaim much faster than we do&lt;br /&gt;
right now.&lt;br /&gt;
&lt;br /&gt;
This will have a noticable effect, though. When inodes are unlinked the space&lt;br /&gt;
consumed by those inodes may not be immediately freed - it will be returned as&lt;br /&gt;
the inodes are processed through the reclaim threads. This means that userspace&lt;br /&gt;
monitoring tools such as &#039;df&#039; may not immediately reflect the result of a&lt;br /&gt;
completed unlink operation. This will be a user visible change in behaviour,&lt;br /&gt;
though in most cases should not affect anyone and for those that it does affect&lt;br /&gt;
a &#039;sync&#039; should be sufficient to wait for the space to be returned.&lt;br /&gt;
&lt;br /&gt;
Now that inodes to be unlinked are out of general circulation, we can make the&lt;br /&gt;
unlinked path more complex. It is desirable to move the unlinked list from the&lt;br /&gt;
inode buffer to the inode core, but that has locking implications for incore&lt;br /&gt;
unlinked. Hence we really need background thread processing to enable this to&lt;br /&gt;
work (i.e. being able to requeue inodes for later processing). To ensure that&lt;br /&gt;
to overhead of this work is not a limiting factor, we will probably need&lt;br /&gt;
multiple workqueue processing threads for this.&lt;br /&gt;
&lt;br /&gt;
Moving the logging to the inode core enables two things - it allows us to keep&lt;br /&gt;
an in-memory copy of the unlinked list off the perag and that allows us to remove&lt;br /&gt;
xfs_inotobp(). The in-memory unlinked list means we don&#039;t have to read and&lt;br /&gt;
traverse the buffers every time we need to find the previous buffer to remove an&lt;br /&gt;
inode from the list, but it does mean we have to take the inode lock. If the&lt;br /&gt;
previous inode is locked, then we can&#039;t remove the inode from the unlinked list&lt;br /&gt;
so we must requeue it for this to occur at a later time.&lt;br /&gt;
&lt;br /&gt;
Combined with the changes to inode create, we effectively will only use the&lt;br /&gt;
inode buffer in the transaction subsystem for marking the region stale when&lt;br /&gt;
freeing an inode chunk from disk (i.e. the default noikeep configuration). If&lt;br /&gt;
we are using large inode allocation, we don&#039;t want to be freeing random inode&lt;br /&gt;
chunks - this will just leave us with fragmented inode regions and undo all the&lt;br /&gt;
good work that was done originally.&lt;br /&gt;
&lt;br /&gt;
To avoid this, we should not be freeing inode chunks as soon as they no longer&lt;br /&gt;
have any empty inodes in them. We should periodically scan the AGI btree&lt;br /&gt;
looking for contiguous chunks that have no inodes allocated in them, and then&lt;br /&gt;
freeing the large contiguous regions we find in one go. It is likely this can&lt;br /&gt;
be done in a single transaction; it&#039;s one extent to be freed, along with a&lt;br /&gt;
contiguous set of records to be removed from the AGI btree so should not&lt;br /&gt;
require logging much at all. Also, the background scanning could be triggered&lt;br /&gt;
by a number of different events - low space in an AG, a large number of free&lt;br /&gt;
inodes in an AG, etc - as it doesn&#039;t need to be done frequently. As a result&lt;br /&gt;
of the lack of frequency that this needs to be done, it can probably be&lt;br /&gt;
handled by a single thread or delayed workqueue.&lt;br /&gt;
&lt;br /&gt;
Further optimisations are possible here - if we rule that the AGI btree is the&lt;br /&gt;
sole place that inodes are marked free or in-use (with the exception of&lt;br /&gt;
unlinked inodes attached to the AGI lists), then we can avoid the need to&lt;br /&gt;
write back unlinked inodes or read newly created inodes from disk.  This would&lt;br /&gt;
require all inodes to effectively use a random generation number assigned at&lt;br /&gt;
create time as we would not be reading it from disk - writing/reading the current&lt;br /&gt;
generation number appears to be the only real reason for doing this I/O. This&lt;br /&gt;
would require extra checks to determine if an inode is unlinked - we&lt;br /&gt;
need to do an imap lookup rather than reading it and then checking it is&lt;br /&gt;
valid if it is not already in memory. Avoiding the I/O, however, will greatly speed&lt;br /&gt;
up create and remove workloads. Note: the impact of this on the bulkstat algorithm&lt;br /&gt;
has not been determined yet.&lt;br /&gt;
&lt;br /&gt;
One of the issues we need to consider with this background inactivation is that&lt;br /&gt;
we will be able to defer a large quantity of inactivation transactions so we are&lt;br /&gt;
going to need to be careful about how much we allow to be queued. Simple queue&lt;br /&gt;
depth throttling should be all that is needed to keep this under control.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Reclaim Optimizations ==&lt;br /&gt;
&lt;br /&gt;
Tracking inodes for reclaim in radix tree: Done&lt;br /&gt;
&lt;br /&gt;
Using RCU for radix tree reclaim walks: Done&lt;br /&gt;
&lt;br /&gt;
Non-blocking background reclaim: Done&lt;br /&gt;
&lt;br /&gt;
Parallelised shrinker based reclaim: Done&lt;br /&gt;
&lt;br /&gt;
Now that we have efficient unlink, we&#039;ve got to handle the reclaim of all the&lt;br /&gt;
inodes that are now dead or simply not referenced. For inodes that are dirty,&lt;br /&gt;
we need to write them out to clean them. For inodes that are clean and not&lt;br /&gt;
unlinked, we need to compress them down for more compact storage. This involves&lt;br /&gt;
some CPU overhead, but it is worth noting that reclaiming of clean inodes&lt;br /&gt;
typically only occurs when we are under memory pressure.&lt;br /&gt;
&lt;br /&gt;
By compressing the XFS inode in this case, we are effectively reducing the&lt;br /&gt;
memory usage of the inode rather than freeing it directly. If we then get&lt;br /&gt;
another operation on that inode (e.g. the working set is slightly larger than&lt;br /&gt;
can be held in linux+XFS inode pairs, we avoid having to read the inode off&lt;br /&gt;
disk again - it simply gets uncompressed out of the cache. In essence we use&lt;br /&gt;
the compressed inode cache as an exclusive second level cache - it has higher&lt;br /&gt;
density than the primary cache and higher load latency and CPU overhead,&lt;br /&gt;
but it still avoids I/O in exactly the same manner as the primary cache.&lt;br /&gt;
&lt;br /&gt;
We cannot allow unrestricted build-up of reclaimable inodes - the memory they&lt;br /&gt;
consume will be large, so we should be aiming to compress reclaimable inodes as&lt;br /&gt;
soon as they are clean.  This will prevent buildup of memory consuming&lt;br /&gt;
uncompressed inodes that are not likely to be referenced again immediately.&lt;br /&gt;
&lt;br /&gt;
This clean inode reclaimation process can be accelerated by triggering reclaim&lt;br /&gt;
on inode I/O completion. If the inode is clean and reclaimable we should&lt;br /&gt;
trigger immediate reclaim processing of that inode.  This will mean that&lt;br /&gt;
reclaim of newly cleaned inodes will not get held up behind reclaim of dirty&lt;br /&gt;
inodes.&lt;br /&gt;
&lt;br /&gt;
For inodes that are unlinked, we can simply free them in reclaim as theƦ&lt;br /&gt;
are no longer in use. We don&#039;t want to poison the compressed cache with&lt;br /&gt;
unlinked inodes, nor do we need to because we can allocate new inodes&lt;br /&gt;
without incurring I/O.&lt;br /&gt;
&lt;br /&gt;
Still, we may end up with lots of inodes queued for reclaim. We may need&lt;br /&gt;
to implement a throttle mechanism to slow down the rate at which inodes&lt;br /&gt;
are queued for reclaimation in the situation where the reclaim process&lt;br /&gt;
is not able to keep up. It should be noted that if we parallelise inode&lt;br /&gt;
writeback we should also be able to parallelise inode reclaim via&lt;br /&gt;
the same mechanism, so the need for throttling may relatively low&lt;br /&gt;
if we can have multiple inodes under reclaim at once.&lt;br /&gt;
&lt;br /&gt;
It should be noted that complexity is exposed by interactions with concurrent&lt;br /&gt;
lookups, especially if we move to RCU locking on the radix tree. Firstly, we&lt;br /&gt;
need to be able to do an atomic swap of the compressed inode for the&lt;br /&gt;
uncompressed inode in the radix tree (and vice versa), to be able to tell them&lt;br /&gt;
apart (magic #), and to have atomic reference counts to ensure we can avoid use&lt;br /&gt;
after free situations when lookups race with compression or freeing.&lt;br /&gt;
&lt;br /&gt;
Secondly, with the complex unlink/reclaim interactions we will need to be&lt;br /&gt;
careful to detect inodes in the process of reclaim - the lookupp process&lt;br /&gt;
will need to do different things depending on the state of reclaim. Indeed,&lt;br /&gt;
we will need to be able to cancel reclaim of an unlinked inode if we try&lt;br /&gt;
to allocate it before it has been fully unlinked or reclaimed. The same&lt;br /&gt;
can be said for an inode in the process of being compressed - if we get&lt;br /&gt;
a lookup during the compression process, we want to return the existing&lt;br /&gt;
inode, not have to wait, re-allocate and uncompress it again. These&lt;br /&gt;
are all solvable issues - they just add complexity.&lt;br /&gt;
&lt;br /&gt;
== Accelerated Reclaim of buftarg Page Cache for Inodes ==&lt;br /&gt;
----------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Per-buftarg buffer LRU reclaim: Done&lt;br /&gt;
&lt;br /&gt;
Per-buftarg shrinker: Done&lt;br /&gt;
&lt;br /&gt;
Per-buffer type reclaim prioritisation: Done&lt;br /&gt;
&lt;br /&gt;
For single use inodes or even read-only inodes, we read them in, use them, then&lt;br /&gt;
reclaim them. With the compressed cache, they&#039;ll get compressed and live a lot&lt;br /&gt;
longer in memory. However, we also will have the inode cluster buffer pages&lt;br /&gt;
sitting in memory for some length of time after the inode was read in. This can&lt;br /&gt;
consume a large amount of memory that will never be used again, and does not&lt;br /&gt;
get reclaimed until they are purged from the LRU by the VM.  It would be&lt;br /&gt;
advantageous to accelerate the reclaim of these pages so that they do not build&lt;br /&gt;
up unneccessarily.&lt;br /&gt;
&lt;br /&gt;
A better method would appear to be to leverage the delayed read queue&lt;br /&gt;
mechanism. This delayed read queue pins read buffers for a short period of&lt;br /&gt;
time, and then if they have not been referenced they get torn down.  If, as&lt;br /&gt;
part of this delayed read buffer teardown procedure we all free the backing&lt;br /&gt;
pages completely, we acheive the exact same result as having our own LRUs to&lt;br /&gt;
manage the page cache. This seems much simpler and a much more holistic&lt;br /&gt;
approach to solving the problem than implementing page LRUs.&lt;br /&gt;
&lt;br /&gt;
== Killing Bufferheads (a.k.a &amp;quot;Die, buggerheads, Die!&amp;quot;) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[This is not strictly about inode caching, but doesn&#039;t fit into&lt;br /&gt;
other areas of development as closely as it does to inode caching&lt;br /&gt;
optimisations.]&lt;br /&gt;
&lt;br /&gt;
XFS is extent based. The Linux page cache is block based. Hence for&lt;br /&gt;
every cached page in memory, we have to attach a structure for mapping&lt;br /&gt;
the blocks on that page back to to the on-disk location. In XFs, we also&lt;br /&gt;
use this to hold state for delayed allocation and unwritten extent blocks&lt;br /&gt;
so the generic code can do the right thing when necessary. We also&lt;br /&gt;
use it to avoid extent lookups at various times within the XFS I/O&lt;br /&gt;
path.&lt;br /&gt;
&lt;br /&gt;
However, this has a massive cost. While XFS might represent the&lt;br /&gt;
disk mapping of a 1GB extent in 24 bytes of memory, the page cache&lt;br /&gt;
requires 262,144 bufferheads (assuming 4k block size) to represent the&lt;br /&gt;
same mapping. That&#039;s roughly 14MB of memory neededtoo represent that.&lt;br /&gt;
&lt;br /&gt;
Chris Mason wrote an extent map representation for page cache state&lt;br /&gt;
and mappings for BTRFS; that code is mostly generic and could be&lt;br /&gt;
adapted to XFS. This would allow us to hold all the page cache state&lt;br /&gt;
in extent format and greatly reduce the memory overhead that it currently&lt;br /&gt;
has. The tradeoff is increased CPU overhead due to tree lookups where&lt;br /&gt;
structure lookups currently are used. Still, this has much lower&lt;br /&gt;
overhead than xfs_bmapi() based lookups, so the penalty is going to&lt;br /&gt;
be lower than if we did these lookups right now.&lt;br /&gt;
&lt;br /&gt;
If we make this change, we would then have three levels of extent&lt;br /&gt;
caching:&lt;br /&gt;
&lt;br /&gt;
	- the BMBT buffers&lt;br /&gt;
	- the XFS incore inode extent tree (iext*)&lt;br /&gt;
	- the page cache extent map tree&lt;br /&gt;
&lt;br /&gt;
Effectively, the XFS incore inode extent tree becomes redundant - all&lt;br /&gt;
the extent state it holds can be moved to the generic page cache tree&lt;br /&gt;
and we can do all our incore operations there. Our logging of changes&lt;br /&gt;
is based on the BMBT buffers, so getting rid of the iext layer would&lt;br /&gt;
not impact the transaction subsystem at all.&lt;br /&gt;
&lt;br /&gt;
Such integration with the generic code will also allow development&lt;br /&gt;
of generic writeback routines for delayed allocation, unwritten&lt;br /&gt;
extents, etc that are not specific to a given filesystem.&lt;br /&gt;
&lt;br /&gt;
== Demand Paging of Large Inode Extent Maps ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Currently the inode extent map is pinned  in memory until the inode is&lt;br /&gt;
reclaimed. Hence an inode with millions of extents will pin a large&lt;br /&gt;
amount of memory and this can cause serious issues in low memory&lt;br /&gt;
situations. Ideally we would like to be able to page the extent&lt;br /&gt;
map in and out once they get to a certain size to avoid this&lt;br /&gt;
problem. This feature requires more investigation before an overall&lt;br /&gt;
approach can be detailed here.&lt;br /&gt;
&lt;br /&gt;
It should be noted that if we move to an extent-based page cache mapping&lt;br /&gt;
tree, the associated extent state tree can be used to track sparse&lt;br /&gt;
regions. That is, regions of the extent map that are not in memory&lt;br /&gt;
can be easily represented and acceesses to an unread region can then&lt;br /&gt;
be used to trigger demand loading.&lt;br /&gt;
&lt;br /&gt;
== Food For Thought (Crazy Ideas) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If we are not using inode buffers for logging changes to inodes, we should&lt;br /&gt;
consider whether we need them at all. What benefit do the buffers bring us when&lt;br /&gt;
all we will use them for is read or write I/O?  Would it be better to go&lt;br /&gt;
straight to the buftarg page cache and do page based I/O via submit_bio()?&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=Improving_inode_Caching&amp;diff=2133</id>
		<title>Improving inode Caching</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=Improving_inode_Caching&amp;diff=2133"/>
		<updated>2010-12-23T03:51:08Z</updated>

		<summary type="html">&lt;p&gt;Dgc: /* Reclaim Optimizations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Future Directions for XFS&lt;br /&gt;
&lt;br /&gt;
== Improving Inode Caching and Operation in XFS ==&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Thousand foot view:&lt;br /&gt;
&lt;br /&gt;
We want to drive inode lookup in a manner that is as parallel, scalable and low&lt;br /&gt;
overhead as possible. This means efficient indexing, lowering memory&lt;br /&gt;
consumption, simplifying the caching heirachy, removing duplication and&lt;br /&gt;
reducing/removing lock traffic.&lt;br /&gt;
&lt;br /&gt;
In addition, we want to provide a good foundation for simplifying inode I/O,&lt;br /&gt;
improving writeback clustering, preventing RMW of inode buffers under memory&lt;br /&gt;
pressure, reducing creation and deletion overhead and removing writeback of&lt;br /&gt;
unlogged changes completely.&lt;br /&gt;
&lt;br /&gt;
There are a variety of features in disconnected trees and patch sets that need&lt;br /&gt;
to be combined to acheive this - the basic structure needed to implement this is&lt;br /&gt;
already in mainline and that is the radix tree inode indexing.  Further&lt;br /&gt;
improvements are going to be based around this structure and using it&lt;br /&gt;
effectively to avoid needing other indexing mechanisms.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Discussion:&lt;br /&gt;
&lt;br /&gt;
== Combining XFS and VFS inodes ==&lt;br /&gt;
----------------------------&lt;br /&gt;
&lt;br /&gt;
Status: Done (October 2008)&lt;br /&gt;
&lt;br /&gt;
== Compressed Inode Cache ==&lt;br /&gt;
-----------------------------&lt;br /&gt;
&lt;br /&gt;
The XFs inode cache uses a lot of memory. We can avoid this problem by making&lt;br /&gt;
use of the compressed inode cache - only the active inodes are held in a&lt;br /&gt;
non-compressed form, hence most inodes will end up being cached in compressed&lt;br /&gt;
form rather than in the XFS/linux inode form.  The compressed form can reduce&lt;br /&gt;
the cached inode footprint to 200-300 bytes per inode instead of 1-1.1k that&lt;br /&gt;
they currently take on a 64bit system. Hence by moving to a compressed cache we&lt;br /&gt;
can greatly increase the number of inodes cached in a given amount of memory&lt;br /&gt;
which more that offsets any comparitive increase we will see from inodes in&lt;br /&gt;
reclaim. the compressed cache should really have a LRU and a shrinker as well&lt;br /&gt;
so that memory pressure will slowly trim it as memory demands occur. [Note:&lt;br /&gt;
this compressed cache is discussed further later on in the reclaim context.]&lt;br /&gt;
&lt;br /&gt;
== Fixed Inode Cache Size ==&lt;br /&gt;
&lt;br /&gt;
It is worth noting that for embedded systems and appliances it may be worth while allowing&lt;br /&gt;
the size of the caches to be fixed. Also, to prevent memory fragmentation&lt;br /&gt;
problems, we could simply allocate that memory to the compressed cache slab.&lt;br /&gt;
In effect, this would become a &#039;static slab&#039; in that it has a bound maximum&lt;br /&gt;
size and never frees and memory. When the cache is full, we reclaim an&lt;br /&gt;
object out of it for reuse - this could be done by triggering the shrinker&lt;br /&gt;
to reclaim from the LRU. This would prevent the compressed inode cache from&lt;br /&gt;
consuming excessive amounts of memory in tightly constrained evironments.&lt;br /&gt;
Such an extension to the slab caches does not look difficult to implement,&lt;br /&gt;
and would allow such customisation with minimal deviation from mainline code.&lt;br /&gt;
&lt;br /&gt;
== Bypassing the Linux Inode Cache ==&lt;br /&gt;
&lt;br /&gt;
Lookups: Done (October 2008)&lt;br /&gt;
&lt;br /&gt;
Tracking dirty inodes: Done&lt;br /&gt;
&lt;br /&gt;
Writeback of dirty inodes: Done&lt;br /&gt;
&lt;br /&gt;
Writeback of dirty pages: still executed the by VFS&lt;br /&gt;
&lt;br /&gt;
Now that we can track dirty inodes ourselves, we can pretty much isolate&lt;br /&gt;
writeback of both data and inodes from the generic pdflush code. If we add a&lt;br /&gt;
hook high up in the pdflush path that simply passes us a writeback control&lt;br /&gt;
structure with the current writeback guidelines, we can do writeback within&lt;br /&gt;
those guidelines in the most optimal fashion for XFS.&lt;br /&gt;
&lt;br /&gt;
== Avoiding the Generic pdflush Code ==&lt;br /&gt;
&lt;br /&gt;
Writeback of inodes via AIL: Done&lt;br /&gt;
&lt;br /&gt;
For pdflush driven writeback, we only want to write back data; all other inode&lt;br /&gt;
writeback should be driven from the AIL (our time ordered dirty metadata list)&lt;br /&gt;
or xfssyncd in a manner that is most optimal for XFS.&lt;br /&gt;
&lt;br /&gt;
Furthermore, if we implement our own pdflush method, we can parallelise it in&lt;br /&gt;
several ways. We can ensure that each filesystem has it&#039;s own flush thread or&lt;br /&gt;
thread pool, we can have a thread pool shared by all filesystems (like pdflush&lt;br /&gt;
currently operates), we can have a flush thread per inode radix tree, and so&lt;br /&gt;
one. The method of paralleisation is open for interpretation, but enabling&lt;br /&gt;
multiple flush threads to operate on a single filesystem is one of the necessary&lt;br /&gt;
requirements to avoid data writeback (and hence delayed allocation) being&lt;br /&gt;
limited to the throughput of a single CPU per filesystem.&lt;br /&gt;
&lt;br /&gt;
== Improving Inode Writeback == &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To optimise inode writeback, we really need to reduce the impact of inode&lt;br /&gt;
buffer read-modify-write cycles. XFS is capable of caching far more inodes in&lt;br /&gt;
memory than it has buffer space available for, so RMW cycles during inode&lt;br /&gt;
writeback under memory pressure are quite common. Firstly, we want to avoid&lt;br /&gt;
blocking pdflush at all costs.  Secondly, we want to issue as much localised&lt;br /&gt;
readahead as possible in ascending offset order to allow both elevator merging&lt;br /&gt;
of readahead and as little seeking as possible. Finally, we want to issue all&lt;br /&gt;
the write cycles as close together as possible to allow the same elevator and&lt;br /&gt;
I/O optimisations to take place.&lt;br /&gt;
&lt;br /&gt;
To do this, firstly we need the non-blocking inode flush semantics to issue&lt;br /&gt;
readahead on buffers that are not up-to-date rather than reading them&lt;br /&gt;
synchronously. Inode writeback already has the interface to handle inodes that&lt;br /&gt;
weren&#039;t flushed - we return EAGAIN from xfs_iflush() and the higher inode&lt;br /&gt;
writeback layers handle this appropriately. It would be easy to add another&lt;br /&gt;
flag to pass down to the buffer layer to say &#039;issue but don&#039;t wait for any&lt;br /&gt;
read&#039;. If we use a radix tree traversal to issue readahead in such a manner,&lt;br /&gt;
we&#039;ll get ascending offset readahead being issued.&lt;br /&gt;
&lt;br /&gt;
One problem with this is that we can issue too much readahead and thrash the&lt;br /&gt;
cache. A possible solution to this is to make the readahead a &#039;delayed read&#039;&lt;br /&gt;
and on I/o completion add it to a queue that holds a reference on the buffer.&lt;br /&gt;
If a followup read occurs soon after, we remove it from the queue and drop that&lt;br /&gt;
reference. This prevents the buffer from being reclaimed in betwen the&lt;br /&gt;
readahead completing and the real read being issued. We should also issue this&lt;br /&gt;
delayed read on buffers that are in the cache so that they don&#039;t get reclaimed&lt;br /&gt;
to make room for the readahead.&lt;br /&gt;
&lt;br /&gt;
To prevent buildup of delayed read buffers, we can periodically purge them -&lt;br /&gt;
those that are older than a given age (say 5 seconds) can be removed from the&lt;br /&gt;
list and their reference dropped. This will free the buffer and allow it&#039;s&lt;br /&gt;
pages to be reclaimed.&lt;br /&gt;
&lt;br /&gt;
Once we have done the readahead pass, we can then do a modify and writeback&lt;br /&gt;
pass over all the inodes, knowing that there will be no read cycles to delay&lt;br /&gt;
this step. Once again, a radix tree traversal gives us ascending order&lt;br /&gt;
writeback and hence the modified buffers we send to the device will be in&lt;br /&gt;
optimal order for merging and minimal seek overhead.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Contiguous Inode Allocation ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To make optimal use of the radix tree cache and enable wide-scale clustering of&lt;br /&gt;
inode writeback across multiple clusters, we really need to ensure that inode&lt;br /&gt;
allocation occurs in large contiguous chunks on disk. Right now we only&lt;br /&gt;
allocate chunks of 64 inodes at a time; ideally we want to allocate a stripe&lt;br /&gt;
unit (or multiple of) full of inodes at a time. This would allow inode&lt;br /&gt;
writeback clustering to do full stripe writes to the underlying RAID if there&lt;br /&gt;
are dirty inodes spanning the entire stripe unit.&lt;br /&gt;
&lt;br /&gt;
The problem with doing this is that we don&#039;t want to introduce the latency of&lt;br /&gt;
creating megabytes of inodes when only one is needed for the current operation.&lt;br /&gt;
Hence we need to push the inode creation into a background thread and use that&lt;br /&gt;
to create contiguous inode chunks asynchronously. This moves the actual on-disk&lt;br /&gt;
allocation of inodes out of the normal create path; it should always be able to&lt;br /&gt;
find a free inode without doing on disk allocation. This will simplify the&lt;br /&gt;
create path by removing the allocate-on-disk-then-retry-the-create double&lt;br /&gt;
transaction that currently occurs.&lt;br /&gt;
&lt;br /&gt;
As an aside, we could preallocate a small amount of inodes in each AG (10-20MB&lt;br /&gt;
of inodes per AG?) without impacting mkfs time too greatly. This would allow&lt;br /&gt;
the filesystem to be used immediately on the first mount without triggering&lt;br /&gt;
lots of background allocation. This could alsobe done after the first mount&lt;br /&gt;
occurs, but that could interfere with typical benchmarking situations. Another&lt;br /&gt;
good reason for this preallocation is that it will help reduce xfs_repair&lt;br /&gt;
runtime for most common filesystem usages.&lt;br /&gt;
&lt;br /&gt;
One of the issues that the background create will cause is a substantial amount&lt;br /&gt;
of log traffic - every inode buffer initialised will be logged in whole. Hence&lt;br /&gt;
if we create a megabyte of inodes, we&#039;ll be causing a megabyte of log traffic&lt;br /&gt;
just for the inode buffers we&#039;ve initialised.  This is relatively simple to fix&lt;br /&gt;
- we don&#039;t log the buffer, we just log the fact that we need to initialise&lt;br /&gt;
inodes in a given range.  In recovery, when we see this transaction, then we&lt;br /&gt;
build the buffers, initialise them and write them out. Hence, we don&#039;t need to&lt;br /&gt;
log the buffers used to initialise the inodes.&lt;br /&gt;
&lt;br /&gt;
Also, we can use the background allocations to keep track of recently allocated&lt;br /&gt;
inode regions in the per-ag. Using that information to select the next inode to&lt;br /&gt;
be used rather than requiring btree searches on every create will greatly reduce&lt;br /&gt;
the CPU overhead of workloads that create lots of new inodes. It is not clear&lt;br /&gt;
whether a single background thread will be able to allocate enough inodes&lt;br /&gt;
to keep up with demand from the rest of the system - we may need multiple&lt;br /&gt;
threads for large configurations.&lt;br /&gt;
&lt;br /&gt;
== Single Block Inode Allocation ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
One of the big problems we have withe filesystems that are approaching&lt;br /&gt;
full is that it can be hard to find a large enough extent to hold 64 inodes.&lt;br /&gt;
We&#039;ve had ENOSPC errors on inode allocation reported on filesystems that&lt;br /&gt;
are only 85% full. This is a sign of free space fragmentation, and it&lt;br /&gt;
prevents inode allocation from succeeding. We could (and should) write&lt;br /&gt;
a free space defragmenter, but that does not solve the problem - it&#039;s&lt;br /&gt;
reactive, not preventative.&lt;br /&gt;
&lt;br /&gt;
The main problem we have is that XFS uses inode chunk size and alignment&lt;br /&gt;
to optimise inode number to disk location conversion. That is, the conversion&lt;br /&gt;
becomes a single set of shifts and masks instead of an AGI btree lookup.&lt;br /&gt;
This optimisation substantially reduces the CPU and I/O overhead of&lt;br /&gt;
inode lookups, but it does limit our flexibility. If we break the&lt;br /&gt;
alignment restriction, every lookup has to go back to a btree search.&lt;br /&gt;
Hence we really want to avoid breaking chunk alignment and size&lt;br /&gt;
rules.&lt;br /&gt;
&lt;br /&gt;
An approach to avoiding violation of this rule is to be able to determine which&lt;br /&gt;
index to look up when parsing the inode number. For example, we could use the&lt;br /&gt;
high bit of the inode number to indicate that it is located in a non-aligned&lt;br /&gt;
inode chunk and hence needs to be looked up in the btree. This would avoid&lt;br /&gt;
the lookup penalty for correctly aligned inode chunks.&lt;br /&gt;
&lt;br /&gt;
If we then redefine the meaning of the contents of the AGI btree record for&lt;br /&gt;
such inode chunks, we do not need a new index to keep these in. Effectively,&lt;br /&gt;
we need to add a bitmask to the record to indicate which blocks inside&lt;br /&gt;
the chunk can actually contain inodes. We still use aligned/sized records,&lt;br /&gt;
but mask out the sections that we are not allowed to allocate inodes in.&lt;br /&gt;
Effectively, this would allow sparse inode chunks. There may be limitations&lt;br /&gt;
on the resolution of sparseness depending on inode size and block size,&lt;br /&gt;
but for the common cases of 4k block size and 256 or 512 byte inodes I&lt;br /&gt;
think we can run a fully sparse mapping for each inode chunk.&lt;br /&gt;
&lt;br /&gt;
This would allow us to allocate inode extents of any alignment and size&lt;br /&gt;
that fits *inside* the existing alignment/size limitations. That is,&lt;br /&gt;
a single extent allocation could not span two btree records, but can&lt;br /&gt;
lie anywhere inside a single record. It also means that we can do&lt;br /&gt;
multiple extent allocations within one btree record to make optimal&lt;br /&gt;
use of the fragmented free space.&lt;br /&gt;
&lt;br /&gt;
It should be noted that this will probably have impact on some of the&lt;br /&gt;
inode cluster buffer mapping and clustering algorithms. It is not clear&lt;br /&gt;
exactly what impact yet, but certainly write clustering will be affected.&lt;br /&gt;
Fortunately we&#039;ll be able to detect the inodes that will have this problem&lt;br /&gt;
by the high bit in the inode number.&lt;br /&gt;
&lt;br /&gt;
== Inode Unlink ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If we turn to look at unlink and reclaim interactions, there are a few&lt;br /&gt;
optimisations that can be made.  Firstly, we don&#039;t need to do inode inactivation&lt;br /&gt;
in reclaim threads - these transactions can easily be pushed to a background&lt;br /&gt;
thread. This means that xfs_inactive would be little more than a vmtruncate()&lt;br /&gt;
call and queuing to a workqueue. This will substantially speed up the processing&lt;br /&gt;
of prune_icache() - we&#039;ll get inodes moved into reclaim much faster than we do&lt;br /&gt;
right now.&lt;br /&gt;
&lt;br /&gt;
This will have a noticable effect, though. When inodes are unlinked the space&lt;br /&gt;
consumed by those inodes may not be immediately freed - it will be returned as&lt;br /&gt;
the inodes are processed through the reclaim threads. This means that userspace&lt;br /&gt;
monitoring tools such as &#039;df&#039; may not immediately reflect the result of a&lt;br /&gt;
completed unlink operation. This will be a user visible change in behaviour,&lt;br /&gt;
though in most cases should not affect anyone and for those that it does affect&lt;br /&gt;
a &#039;sync&#039; should be sufficient to wait for the space to be returned.&lt;br /&gt;
&lt;br /&gt;
Now that inodes to be unlinked are out of general circulation, we can make the&lt;br /&gt;
unlinked path more complex. It is desirable to move the unlinked list from the&lt;br /&gt;
inode buffer to the inode core, but that has locking implications for incore&lt;br /&gt;
unlinked. Hence we really need background thread processing to enable this to&lt;br /&gt;
work (i.e. being able to requeue inodes for later processing). To ensure that&lt;br /&gt;
to overhead of this work is not a limiting factor, we will probably need&lt;br /&gt;
multiple workqueue processing threads for this.&lt;br /&gt;
&lt;br /&gt;
Moving the logging to the inode core enables two things - it allows us to keep&lt;br /&gt;
an in-memory copy of the unlinked list off the perag and that allows us to remove&lt;br /&gt;
xfs_inotobp(). The in-memory unlinked list means we don&#039;t have to read and&lt;br /&gt;
traverse the buffers every time we need to find the previous buffer to remove an&lt;br /&gt;
inode from the list, but it does mean we have to take the inode lock. If the&lt;br /&gt;
previous inode is locked, then we can&#039;t remove the inode from the unlinked list&lt;br /&gt;
so we must requeue it for this to occur at a later time.&lt;br /&gt;
&lt;br /&gt;
Combined with the changes to inode create, we effectively will only use the&lt;br /&gt;
inode buffer in the transaction subsystem for marking the region stale when&lt;br /&gt;
freeing an inode chunk from disk (i.e. the default noikeep configuration). If&lt;br /&gt;
we are using large inode allocation, we don&#039;t want to be freeing random inode&lt;br /&gt;
chunks - this will just leave us with fragmented inode regions and undo all the&lt;br /&gt;
good work that was done originally.&lt;br /&gt;
&lt;br /&gt;
To avoid this, we should not be freeing inode chunks as soon as they no longer&lt;br /&gt;
have any empty inodes in them. We should periodically scan the AGI btree&lt;br /&gt;
looking for contiguous chunks that have no inodes allocated in them, and then&lt;br /&gt;
freeing the large contiguous regions we find in one go. It is likely this can&lt;br /&gt;
be done in a single transaction; it&#039;s one extent to be freed, along with a&lt;br /&gt;
contiguous set of records to be removed from the AGI btree so should not&lt;br /&gt;
require logging much at all. Also, the background scanning could be triggered&lt;br /&gt;
by a number of different events - low space in an AG, a large number of free&lt;br /&gt;
inodes in an AG, etc - as it doesn&#039;t need to be done frequently. As a result&lt;br /&gt;
of the lack of frequency that this needs to be done, it can probably be&lt;br /&gt;
handled by a single thread or delayed workqueue.&lt;br /&gt;
&lt;br /&gt;
Further optimisations are possible here - if we rule that the AGI btree is the&lt;br /&gt;
sole place that inodes are marked free or in-use (with the exception of&lt;br /&gt;
unlinked inodes attached to the AGI lists), then we can avoid the need to&lt;br /&gt;
write back unlinked inodes or read newly created inodes from disk.  This would&lt;br /&gt;
require all inodes to effectively use a random generation number assigned at&lt;br /&gt;
create time as we would not be reading it from disk - writing/reading the current&lt;br /&gt;
generation number appears to be the only real reason for doing this I/O. This&lt;br /&gt;
would require extra checks to determine if an inode is unlinked - we&lt;br /&gt;
need to do an imap lookup rather than reading it and then checking it is&lt;br /&gt;
valid if it is not already in memory. Avoiding the I/O, however, will greatly speed&lt;br /&gt;
up create and remove workloads. Note: the impact of this on the bulkstat algorithm&lt;br /&gt;
has not been determined yet.&lt;br /&gt;
&lt;br /&gt;
One of the issues we need to consider with this background inactivation is that&lt;br /&gt;
we will be able to defer a large quantity of inactivation transactions so we are&lt;br /&gt;
going to need to be careful about how much we allow to be queued. Simple queue&lt;br /&gt;
depth throttling should be all that is needed to keep this under control.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Reclaim Optimizations ==&lt;br /&gt;
&lt;br /&gt;
Tracking inodes for reclaim in radix tree: Done&lt;br /&gt;
&lt;br /&gt;
Using RCU for radix tree reclaim walks: Done&lt;br /&gt;
&lt;br /&gt;
Non-blocking background reclaim: Done&lt;br /&gt;
&lt;br /&gt;
Parallelised shrinker based reclaim: Done&lt;br /&gt;
&lt;br /&gt;
Now that we have efficient unlink, we&#039;ve got to handle the reclaim of all the&lt;br /&gt;
inodes that are now dead or simply not referenced. For inodes that are dirty,&lt;br /&gt;
we need to write them out to clean them. For inodes that are clean and not&lt;br /&gt;
unlinked, we need to compress them down for more compact storage. This involves&lt;br /&gt;
some CPU overhead, but it is worth noting that reclaiming of clean inodes&lt;br /&gt;
typically only occurs when we are under memory pressure.&lt;br /&gt;
&lt;br /&gt;
By compressing the XFS inode in this case, we are effectively reducing the&lt;br /&gt;
memory usage of the inode rather than freeing it directly. If we then get&lt;br /&gt;
another operation on that inode (e.g. the working set is slightly larger than&lt;br /&gt;
can be held in linux+XFS inode pairs, we avoid having to read the inode off&lt;br /&gt;
disk again - it simply gets uncompressed out of the cache. In essence we use&lt;br /&gt;
the compressed inode cache as an exclusive second level cache - it has higher&lt;br /&gt;
density than the primary cache and higher load latency and CPU overhead,&lt;br /&gt;
but it still avoids I/O in exactly the same manner as the primary cache.&lt;br /&gt;
&lt;br /&gt;
We cannot allow unrestricted build-up of reclaimable inodes - the memory they&lt;br /&gt;
consume will be large, so we should be aiming to compress reclaimable inodes as&lt;br /&gt;
soon as they are clean.  This will prevent buildup of memory consuming&lt;br /&gt;
uncompressed inodes that are not likely to be referenced again immediately.&lt;br /&gt;
&lt;br /&gt;
This clean inode reclaimation process can be accelerated by triggering reclaim&lt;br /&gt;
on inode I/O completion. If the inode is clean and reclaimable we should&lt;br /&gt;
trigger immediate reclaim processing of that inode.  This will mean that&lt;br /&gt;
reclaim of newly cleaned inodes will not get held up behind reclaim of dirty&lt;br /&gt;
inodes.&lt;br /&gt;
&lt;br /&gt;
For inodes that are unlinked, we can simply free them in reclaim as theƦ&lt;br /&gt;
are no longer in use. We don&#039;t want to poison the compressed cache with&lt;br /&gt;
unlinked inodes, nor do we need to because we can allocate new inodes&lt;br /&gt;
without incurring I/O.&lt;br /&gt;
&lt;br /&gt;
Still, we may end up with lots of inodes queued for reclaim. We may need&lt;br /&gt;
to implement a throttle mechanism to slow down the rate at which inodes&lt;br /&gt;
are queued for reclaimation in the situation where the reclaim process&lt;br /&gt;
is not able to keep up. It should be noted that if we parallelise inode&lt;br /&gt;
writeback we should also be able to parallelise inode reclaim via&lt;br /&gt;
the same mechanism, so the need for throttling may relatively low&lt;br /&gt;
if we can have multiple inodes under reclaim at once.&lt;br /&gt;
&lt;br /&gt;
It should be noted that complexity is exposed by interactions with concurrent&lt;br /&gt;
lookups, especially if we move to RCU locking on the radix tree. Firstly, we&lt;br /&gt;
need to be able to do an atomic swap of the compressed inode for the&lt;br /&gt;
uncompressed inode in the radix tree (and vice versa), to be able to tell them&lt;br /&gt;
apart (magic #), and to have atomic reference counts to ensure we can avoid use&lt;br /&gt;
after free situations when lookups race with compression or freeing.&lt;br /&gt;
&lt;br /&gt;
Secondly, with the complex unlink/reclaim interactions we will need to be&lt;br /&gt;
careful to detect inodes in the process of reclaim - the lookupp process&lt;br /&gt;
will need to do different things depending on the state of reclaim. Indeed,&lt;br /&gt;
we will need to be able to cancel reclaim of an unlinked inode if we try&lt;br /&gt;
to allocate it before it has been fully unlinked or reclaimed. The same&lt;br /&gt;
can be said for an inode in the process of being compressed - if we get&lt;br /&gt;
a lookup during the compression process, we want to return the existing&lt;br /&gt;
inode, not have to wait, re-allocate and uncompress it again. These&lt;br /&gt;
are all solvable issues - they just add complexity.&lt;br /&gt;
&lt;br /&gt;
== Accelerated Reclaim of buftarg Page Cache for Inodes ==&lt;br /&gt;
----------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Per-buftarg buffer LRU reclaim: Done&lt;br /&gt;
&lt;br /&gt;
Per-buftarg shrinker: Done&lt;br /&gt;
&lt;br /&gt;
Per-buffer type reclaim prioritisation: Done&lt;br /&gt;
&lt;br /&gt;
For single use inodes or even read-only inodes, we read them in, use them, then&lt;br /&gt;
reclaim them. With the compressed cache, they&#039;ll get compressed and live a lot&lt;br /&gt;
longer in memory. However, we also will have the inode cluster buffer pages&lt;br /&gt;
sitting in memory for some length of time after the inode was read in. This can&lt;br /&gt;
consume a large amount of memory that will never be used again, and does not&lt;br /&gt;
get reclaimed until they are purged from the LRU by the VM.  It would be&lt;br /&gt;
advantageous to accelerate the reclaim of these pages so that they do not build&lt;br /&gt;
up unneccessarily.&lt;br /&gt;
&lt;br /&gt;
A better method would appear to be to leverage the delayed read queue&lt;br /&gt;
mechanism. This delayed read queue pins read buffers for a short period of&lt;br /&gt;
time, and then if they have not been referenced they get torn down.  If, as&lt;br /&gt;
part of this delayed read buffer teardown procedure we all free the backing&lt;br /&gt;
pages completely, we acheive the exact same result as having our own LRUs to&lt;br /&gt;
manage the page cache. This seems much simpler and a much more holistic&lt;br /&gt;
approach to solving the problem than implementing page LRUs.&lt;br /&gt;
&lt;br /&gt;
== Killing Bufferheads (a.k.a &amp;quot;Die, buggerheads, Die!&amp;quot;) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[This is not strictly about inode caching, but doesn&#039;t fit into&lt;br /&gt;
other areas of development as closely as it does to inode caching&lt;br /&gt;
optimisations.]&lt;br /&gt;
&lt;br /&gt;
XFS is extent based. The Linux page cache is block based. Hence for&lt;br /&gt;
every cached page in memory, we have to attach a structure for mapping&lt;br /&gt;
the blocks on that page back to to the on-disk location. In XFs, we also&lt;br /&gt;
use this to hold state for delayed allocation and unwritten extent blocks&lt;br /&gt;
so the generic code can do the right thing when necessary. We also&lt;br /&gt;
use it to avoid extent lookups at various times within the XFS I/O&lt;br /&gt;
path.&lt;br /&gt;
&lt;br /&gt;
However, this has a massive cost. While XFS might represent the&lt;br /&gt;
disk mapping of a 1GB extent in 24 bytes of memory, the page cache&lt;br /&gt;
requires 262,144 bufferheads (assuming 4k block size) to represent the&lt;br /&gt;
same mapping. That&#039;s roughly 14MB of memory neededtoo represent that.&lt;br /&gt;
&lt;br /&gt;
Chris Mason wrote an extent map representation for page cache state&lt;br /&gt;
and mappings for BTRFS; that code is mostly generic and could be&lt;br /&gt;
adapted to XFS. This would allow us to hold all the page cache state&lt;br /&gt;
in extent format and greatly reduce the memory overhead that it currently&lt;br /&gt;
has. The tradeoff is increased CPU overhead due to tree lookups where&lt;br /&gt;
structure lookups currently are used. Still, this has much lower&lt;br /&gt;
overhead than xfs_bmapi() based lookups, so the penalty is going to&lt;br /&gt;
be lower than if we did these lookups right now.&lt;br /&gt;
&lt;br /&gt;
If we make this change, we would then have three levels of extent&lt;br /&gt;
caching:&lt;br /&gt;
&lt;br /&gt;
	- the BMBT buffers&lt;br /&gt;
	- the XFS incore inode extent tree (iext*)&lt;br /&gt;
	- the page cache extent map tree&lt;br /&gt;
&lt;br /&gt;
Effectively, the XFS incore inode extent tree becomes redundant - all&lt;br /&gt;
the extent state it holds can be moved to the generic page cache tree&lt;br /&gt;
and we can do all our incore operations there. Our logging of changes&lt;br /&gt;
is based on the BMBT buffers, so getting rid of the iext layer would&lt;br /&gt;
not impact the transaction subsystem at all.&lt;br /&gt;
&lt;br /&gt;
Such integration with the generic code will also allow development&lt;br /&gt;
of generic writeback routines for delayed allocation, unwritten&lt;br /&gt;
extents, etc that are not specific to a given filesystem.&lt;br /&gt;
&lt;br /&gt;
== Demand Paging of Large Inode Extent Maps ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Currently the inode extent map is pinned  in memory until the inode is&lt;br /&gt;
reclaimed. Hence an inode with millions of extents will pin a large&lt;br /&gt;
amount of memory and this can cause serious issues in low memory&lt;br /&gt;
situations. Ideally we would like to be able to page the extent&lt;br /&gt;
map in and out once they get to a certain size to avoid this&lt;br /&gt;
problem. This feature requires more investigation before an overall&lt;br /&gt;
approach can be detailed here.&lt;br /&gt;
&lt;br /&gt;
It should be noted that if we move to an extent-based page cache mapping&lt;br /&gt;
tree, the associated extent state tree can be used to track sparse&lt;br /&gt;
regions. That is, regions of the extent map that are not in memory&lt;br /&gt;
can be easily represented and acceesses to an unread region can then&lt;br /&gt;
be used to trigger demand loading.&lt;br /&gt;
&lt;br /&gt;
== Food For Thought (Crazy Ideas) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If we are not using inode buffers for logging changes to inodes, we should&lt;br /&gt;
consider whether we need them at all. What benefit do the buffers bring us when&lt;br /&gt;
all we will use them for is read or write I/O?  Would it be better to go&lt;br /&gt;
straight to the buftarg page cache and do page based I/O via submit_bio()?&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=Improving_inode_Caching&amp;diff=2132</id>
		<title>Improving inode Caching</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=Improving_inode_Caching&amp;diff=2132"/>
		<updated>2010-12-23T03:50:49Z</updated>

		<summary type="html">&lt;p&gt;Dgc: /* Accelerated Reclaim of buftarg Page Cache for Inodes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Future Directions for XFS&lt;br /&gt;
&lt;br /&gt;
== Improving Inode Caching and Operation in XFS ==&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Thousand foot view:&lt;br /&gt;
&lt;br /&gt;
We want to drive inode lookup in a manner that is as parallel, scalable and low&lt;br /&gt;
overhead as possible. This means efficient indexing, lowering memory&lt;br /&gt;
consumption, simplifying the caching heirachy, removing duplication and&lt;br /&gt;
reducing/removing lock traffic.&lt;br /&gt;
&lt;br /&gt;
In addition, we want to provide a good foundation for simplifying inode I/O,&lt;br /&gt;
improving writeback clustering, preventing RMW of inode buffers under memory&lt;br /&gt;
pressure, reducing creation and deletion overhead and removing writeback of&lt;br /&gt;
unlogged changes completely.&lt;br /&gt;
&lt;br /&gt;
There are a variety of features in disconnected trees and patch sets that need&lt;br /&gt;
to be combined to acheive this - the basic structure needed to implement this is&lt;br /&gt;
already in mainline and that is the radix tree inode indexing.  Further&lt;br /&gt;
improvements are going to be based around this structure and using it&lt;br /&gt;
effectively to avoid needing other indexing mechanisms.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Discussion:&lt;br /&gt;
&lt;br /&gt;
== Combining XFS and VFS inodes ==&lt;br /&gt;
----------------------------&lt;br /&gt;
&lt;br /&gt;
Status: Done (October 2008)&lt;br /&gt;
&lt;br /&gt;
== Compressed Inode Cache ==&lt;br /&gt;
-----------------------------&lt;br /&gt;
&lt;br /&gt;
The XFs inode cache uses a lot of memory. We can avoid this problem by making&lt;br /&gt;
use of the compressed inode cache - only the active inodes are held in a&lt;br /&gt;
non-compressed form, hence most inodes will end up being cached in compressed&lt;br /&gt;
form rather than in the XFS/linux inode form.  The compressed form can reduce&lt;br /&gt;
the cached inode footprint to 200-300 bytes per inode instead of 1-1.1k that&lt;br /&gt;
they currently take on a 64bit system. Hence by moving to a compressed cache we&lt;br /&gt;
can greatly increase the number of inodes cached in a given amount of memory&lt;br /&gt;
which more that offsets any comparitive increase we will see from inodes in&lt;br /&gt;
reclaim. the compressed cache should really have a LRU and a shrinker as well&lt;br /&gt;
so that memory pressure will slowly trim it as memory demands occur. [Note:&lt;br /&gt;
this compressed cache is discussed further later on in the reclaim context.]&lt;br /&gt;
&lt;br /&gt;
== Fixed Inode Cache Size ==&lt;br /&gt;
&lt;br /&gt;
It is worth noting that for embedded systems and appliances it may be worth while allowing&lt;br /&gt;
the size of the caches to be fixed. Also, to prevent memory fragmentation&lt;br /&gt;
problems, we could simply allocate that memory to the compressed cache slab.&lt;br /&gt;
In effect, this would become a &#039;static slab&#039; in that it has a bound maximum&lt;br /&gt;
size and never frees and memory. When the cache is full, we reclaim an&lt;br /&gt;
object out of it for reuse - this could be done by triggering the shrinker&lt;br /&gt;
to reclaim from the LRU. This would prevent the compressed inode cache from&lt;br /&gt;
consuming excessive amounts of memory in tightly constrained evironments.&lt;br /&gt;
Such an extension to the slab caches does not look difficult to implement,&lt;br /&gt;
and would allow such customisation with minimal deviation from mainline code.&lt;br /&gt;
&lt;br /&gt;
== Bypassing the Linux Inode Cache ==&lt;br /&gt;
&lt;br /&gt;
Lookups: Done (October 2008)&lt;br /&gt;
&lt;br /&gt;
Tracking dirty inodes: Done&lt;br /&gt;
&lt;br /&gt;
Writeback of dirty inodes: Done&lt;br /&gt;
&lt;br /&gt;
Writeback of dirty pages: still executed the by VFS&lt;br /&gt;
&lt;br /&gt;
Now that we can track dirty inodes ourselves, we can pretty much isolate&lt;br /&gt;
writeback of both data and inodes from the generic pdflush code. If we add a&lt;br /&gt;
hook high up in the pdflush path that simply passes us a writeback control&lt;br /&gt;
structure with the current writeback guidelines, we can do writeback within&lt;br /&gt;
those guidelines in the most optimal fashion for XFS.&lt;br /&gt;
&lt;br /&gt;
== Avoiding the Generic pdflush Code ==&lt;br /&gt;
&lt;br /&gt;
Writeback of inodes via AIL: Done&lt;br /&gt;
&lt;br /&gt;
For pdflush driven writeback, we only want to write back data; all other inode&lt;br /&gt;
writeback should be driven from the AIL (our time ordered dirty metadata list)&lt;br /&gt;
or xfssyncd in a manner that is most optimal for XFS.&lt;br /&gt;
&lt;br /&gt;
Furthermore, if we implement our own pdflush method, we can parallelise it in&lt;br /&gt;
several ways. We can ensure that each filesystem has it&#039;s own flush thread or&lt;br /&gt;
thread pool, we can have a thread pool shared by all filesystems (like pdflush&lt;br /&gt;
currently operates), we can have a flush thread per inode radix tree, and so&lt;br /&gt;
one. The method of paralleisation is open for interpretation, but enabling&lt;br /&gt;
multiple flush threads to operate on a single filesystem is one of the necessary&lt;br /&gt;
requirements to avoid data writeback (and hence delayed allocation) being&lt;br /&gt;
limited to the throughput of a single CPU per filesystem.&lt;br /&gt;
&lt;br /&gt;
== Improving Inode Writeback == &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To optimise inode writeback, we really need to reduce the impact of inode&lt;br /&gt;
buffer read-modify-write cycles. XFS is capable of caching far more inodes in&lt;br /&gt;
memory than it has buffer space available for, so RMW cycles during inode&lt;br /&gt;
writeback under memory pressure are quite common. Firstly, we want to avoid&lt;br /&gt;
blocking pdflush at all costs.  Secondly, we want to issue as much localised&lt;br /&gt;
readahead as possible in ascending offset order to allow both elevator merging&lt;br /&gt;
of readahead and as little seeking as possible. Finally, we want to issue all&lt;br /&gt;
the write cycles as close together as possible to allow the same elevator and&lt;br /&gt;
I/O optimisations to take place.&lt;br /&gt;
&lt;br /&gt;
To do this, firstly we need the non-blocking inode flush semantics to issue&lt;br /&gt;
readahead on buffers that are not up-to-date rather than reading them&lt;br /&gt;
synchronously. Inode writeback already has the interface to handle inodes that&lt;br /&gt;
weren&#039;t flushed - we return EAGAIN from xfs_iflush() and the higher inode&lt;br /&gt;
writeback layers handle this appropriately. It would be easy to add another&lt;br /&gt;
flag to pass down to the buffer layer to say &#039;issue but don&#039;t wait for any&lt;br /&gt;
read&#039;. If we use a radix tree traversal to issue readahead in such a manner,&lt;br /&gt;
we&#039;ll get ascending offset readahead being issued.&lt;br /&gt;
&lt;br /&gt;
One problem with this is that we can issue too much readahead and thrash the&lt;br /&gt;
cache. A possible solution to this is to make the readahead a &#039;delayed read&#039;&lt;br /&gt;
and on I/o completion add it to a queue that holds a reference on the buffer.&lt;br /&gt;
If a followup read occurs soon after, we remove it from the queue and drop that&lt;br /&gt;
reference. This prevents the buffer from being reclaimed in betwen the&lt;br /&gt;
readahead completing and the real read being issued. We should also issue this&lt;br /&gt;
delayed read on buffers that are in the cache so that they don&#039;t get reclaimed&lt;br /&gt;
to make room for the readahead.&lt;br /&gt;
&lt;br /&gt;
To prevent buildup of delayed read buffers, we can periodically purge them -&lt;br /&gt;
those that are older than a given age (say 5 seconds) can be removed from the&lt;br /&gt;
list and their reference dropped. This will free the buffer and allow it&#039;s&lt;br /&gt;
pages to be reclaimed.&lt;br /&gt;
&lt;br /&gt;
Once we have done the readahead pass, we can then do a modify and writeback&lt;br /&gt;
pass over all the inodes, knowing that there will be no read cycles to delay&lt;br /&gt;
this step. Once again, a radix tree traversal gives us ascending order&lt;br /&gt;
writeback and hence the modified buffers we send to the device will be in&lt;br /&gt;
optimal order for merging and minimal seek overhead.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Contiguous Inode Allocation ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To make optimal use of the radix tree cache and enable wide-scale clustering of&lt;br /&gt;
inode writeback across multiple clusters, we really need to ensure that inode&lt;br /&gt;
allocation occurs in large contiguous chunks on disk. Right now we only&lt;br /&gt;
allocate chunks of 64 inodes at a time; ideally we want to allocate a stripe&lt;br /&gt;
unit (or multiple of) full of inodes at a time. This would allow inode&lt;br /&gt;
writeback clustering to do full stripe writes to the underlying RAID if there&lt;br /&gt;
are dirty inodes spanning the entire stripe unit.&lt;br /&gt;
&lt;br /&gt;
The problem with doing this is that we don&#039;t want to introduce the latency of&lt;br /&gt;
creating megabytes of inodes when only one is needed for the current operation.&lt;br /&gt;
Hence we need to push the inode creation into a background thread and use that&lt;br /&gt;
to create contiguous inode chunks asynchronously. This moves the actual on-disk&lt;br /&gt;
allocation of inodes out of the normal create path; it should always be able to&lt;br /&gt;
find a free inode without doing on disk allocation. This will simplify the&lt;br /&gt;
create path by removing the allocate-on-disk-then-retry-the-create double&lt;br /&gt;
transaction that currently occurs.&lt;br /&gt;
&lt;br /&gt;
As an aside, we could preallocate a small amount of inodes in each AG (10-20MB&lt;br /&gt;
of inodes per AG?) without impacting mkfs time too greatly. This would allow&lt;br /&gt;
the filesystem to be used immediately on the first mount without triggering&lt;br /&gt;
lots of background allocation. This could alsobe done after the first mount&lt;br /&gt;
occurs, but that could interfere with typical benchmarking situations. Another&lt;br /&gt;
good reason for this preallocation is that it will help reduce xfs_repair&lt;br /&gt;
runtime for most common filesystem usages.&lt;br /&gt;
&lt;br /&gt;
One of the issues that the background create will cause is a substantial amount&lt;br /&gt;
of log traffic - every inode buffer initialised will be logged in whole. Hence&lt;br /&gt;
if we create a megabyte of inodes, we&#039;ll be causing a megabyte of log traffic&lt;br /&gt;
just for the inode buffers we&#039;ve initialised.  This is relatively simple to fix&lt;br /&gt;
- we don&#039;t log the buffer, we just log the fact that we need to initialise&lt;br /&gt;
inodes in a given range.  In recovery, when we see this transaction, then we&lt;br /&gt;
build the buffers, initialise them and write them out. Hence, we don&#039;t need to&lt;br /&gt;
log the buffers used to initialise the inodes.&lt;br /&gt;
&lt;br /&gt;
Also, we can use the background allocations to keep track of recently allocated&lt;br /&gt;
inode regions in the per-ag. Using that information to select the next inode to&lt;br /&gt;
be used rather than requiring btree searches on every create will greatly reduce&lt;br /&gt;
the CPU overhead of workloads that create lots of new inodes. It is not clear&lt;br /&gt;
whether a single background thread will be able to allocate enough inodes&lt;br /&gt;
to keep up with demand from the rest of the system - we may need multiple&lt;br /&gt;
threads for large configurations.&lt;br /&gt;
&lt;br /&gt;
== Single Block Inode Allocation ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
One of the big problems we have withe filesystems that are approaching&lt;br /&gt;
full is that it can be hard to find a large enough extent to hold 64 inodes.&lt;br /&gt;
We&#039;ve had ENOSPC errors on inode allocation reported on filesystems that&lt;br /&gt;
are only 85% full. This is a sign of free space fragmentation, and it&lt;br /&gt;
prevents inode allocation from succeeding. We could (and should) write&lt;br /&gt;
a free space defragmenter, but that does not solve the problem - it&#039;s&lt;br /&gt;
reactive, not preventative.&lt;br /&gt;
&lt;br /&gt;
The main problem we have is that XFS uses inode chunk size and alignment&lt;br /&gt;
to optimise inode number to disk location conversion. That is, the conversion&lt;br /&gt;
becomes a single set of shifts and masks instead of an AGI btree lookup.&lt;br /&gt;
This optimisation substantially reduces the CPU and I/O overhead of&lt;br /&gt;
inode lookups, but it does limit our flexibility. If we break the&lt;br /&gt;
alignment restriction, every lookup has to go back to a btree search.&lt;br /&gt;
Hence we really want to avoid breaking chunk alignment and size&lt;br /&gt;
rules.&lt;br /&gt;
&lt;br /&gt;
An approach to avoiding violation of this rule is to be able to determine which&lt;br /&gt;
index to look up when parsing the inode number. For example, we could use the&lt;br /&gt;
high bit of the inode number to indicate that it is located in a non-aligned&lt;br /&gt;
inode chunk and hence needs to be looked up in the btree. This would avoid&lt;br /&gt;
the lookup penalty for correctly aligned inode chunks.&lt;br /&gt;
&lt;br /&gt;
If we then redefine the meaning of the contents of the AGI btree record for&lt;br /&gt;
such inode chunks, we do not need a new index to keep these in. Effectively,&lt;br /&gt;
we need to add a bitmask to the record to indicate which blocks inside&lt;br /&gt;
the chunk can actually contain inodes. We still use aligned/sized records,&lt;br /&gt;
but mask out the sections that we are not allowed to allocate inodes in.&lt;br /&gt;
Effectively, this would allow sparse inode chunks. There may be limitations&lt;br /&gt;
on the resolution of sparseness depending on inode size and block size,&lt;br /&gt;
but for the common cases of 4k block size and 256 or 512 byte inodes I&lt;br /&gt;
think we can run a fully sparse mapping for each inode chunk.&lt;br /&gt;
&lt;br /&gt;
This would allow us to allocate inode extents of any alignment and size&lt;br /&gt;
that fits *inside* the existing alignment/size limitations. That is,&lt;br /&gt;
a single extent allocation could not span two btree records, but can&lt;br /&gt;
lie anywhere inside a single record. It also means that we can do&lt;br /&gt;
multiple extent allocations within one btree record to make optimal&lt;br /&gt;
use of the fragmented free space.&lt;br /&gt;
&lt;br /&gt;
It should be noted that this will probably have impact on some of the&lt;br /&gt;
inode cluster buffer mapping and clustering algorithms. It is not clear&lt;br /&gt;
exactly what impact yet, but certainly write clustering will be affected.&lt;br /&gt;
Fortunately we&#039;ll be able to detect the inodes that will have this problem&lt;br /&gt;
by the high bit in the inode number.&lt;br /&gt;
&lt;br /&gt;
== Inode Unlink ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If we turn to look at unlink and reclaim interactions, there are a few&lt;br /&gt;
optimisations that can be made.  Firstly, we don&#039;t need to do inode inactivation&lt;br /&gt;
in reclaim threads - these transactions can easily be pushed to a background&lt;br /&gt;
thread. This means that xfs_inactive would be little more than a vmtruncate()&lt;br /&gt;
call and queuing to a workqueue. This will substantially speed up the processing&lt;br /&gt;
of prune_icache() - we&#039;ll get inodes moved into reclaim much faster than we do&lt;br /&gt;
right now.&lt;br /&gt;
&lt;br /&gt;
This will have a noticable effect, though. When inodes are unlinked the space&lt;br /&gt;
consumed by those inodes may not be immediately freed - it will be returned as&lt;br /&gt;
the inodes are processed through the reclaim threads. This means that userspace&lt;br /&gt;
monitoring tools such as &#039;df&#039; may not immediately reflect the result of a&lt;br /&gt;
completed unlink operation. This will be a user visible change in behaviour,&lt;br /&gt;
though in most cases should not affect anyone and for those that it does affect&lt;br /&gt;
a &#039;sync&#039; should be sufficient to wait for the space to be returned.&lt;br /&gt;
&lt;br /&gt;
Now that inodes to be unlinked are out of general circulation, we can make the&lt;br /&gt;
unlinked path more complex. It is desirable to move the unlinked list from the&lt;br /&gt;
inode buffer to the inode core, but that has locking implications for incore&lt;br /&gt;
unlinked. Hence we really need background thread processing to enable this to&lt;br /&gt;
work (i.e. being able to requeue inodes for later processing). To ensure that&lt;br /&gt;
to overhead of this work is not a limiting factor, we will probably need&lt;br /&gt;
multiple workqueue processing threads for this.&lt;br /&gt;
&lt;br /&gt;
Moving the logging to the inode core enables two things - it allows us to keep&lt;br /&gt;
an in-memory copy of the unlinked list off the perag and that allows us to remove&lt;br /&gt;
xfs_inotobp(). The in-memory unlinked list means we don&#039;t have to read and&lt;br /&gt;
traverse the buffers every time we need to find the previous buffer to remove an&lt;br /&gt;
inode from the list, but it does mean we have to take the inode lock. If the&lt;br /&gt;
previous inode is locked, then we can&#039;t remove the inode from the unlinked list&lt;br /&gt;
so we must requeue it for this to occur at a later time.&lt;br /&gt;
&lt;br /&gt;
Combined with the changes to inode create, we effectively will only use the&lt;br /&gt;
inode buffer in the transaction subsystem for marking the region stale when&lt;br /&gt;
freeing an inode chunk from disk (i.e. the default noikeep configuration). If&lt;br /&gt;
we are using large inode allocation, we don&#039;t want to be freeing random inode&lt;br /&gt;
chunks - this will just leave us with fragmented inode regions and undo all the&lt;br /&gt;
good work that was done originally.&lt;br /&gt;
&lt;br /&gt;
To avoid this, we should not be freeing inode chunks as soon as they no longer&lt;br /&gt;
have any empty inodes in them. We should periodically scan the AGI btree&lt;br /&gt;
looking for contiguous chunks that have no inodes allocated in them, and then&lt;br /&gt;
freeing the large contiguous regions we find in one go. It is likely this can&lt;br /&gt;
be done in a single transaction; it&#039;s one extent to be freed, along with a&lt;br /&gt;
contiguous set of records to be removed from the AGI btree so should not&lt;br /&gt;
require logging much at all. Also, the background scanning could be triggered&lt;br /&gt;
by a number of different events - low space in an AG, a large number of free&lt;br /&gt;
inodes in an AG, etc - as it doesn&#039;t need to be done frequently. As a result&lt;br /&gt;
of the lack of frequency that this needs to be done, it can probably be&lt;br /&gt;
handled by a single thread or delayed workqueue.&lt;br /&gt;
&lt;br /&gt;
Further optimisations are possible here - if we rule that the AGI btree is the&lt;br /&gt;
sole place that inodes are marked free or in-use (with the exception of&lt;br /&gt;
unlinked inodes attached to the AGI lists), then we can avoid the need to&lt;br /&gt;
write back unlinked inodes or read newly created inodes from disk.  This would&lt;br /&gt;
require all inodes to effectively use a random generation number assigned at&lt;br /&gt;
create time as we would not be reading it from disk - writing/reading the current&lt;br /&gt;
generation number appears to be the only real reason for doing this I/O. This&lt;br /&gt;
would require extra checks to determine if an inode is unlinked - we&lt;br /&gt;
need to do an imap lookup rather than reading it and then checking it is&lt;br /&gt;
valid if it is not already in memory. Avoiding the I/O, however, will greatly speed&lt;br /&gt;
up create and remove workloads. Note: the impact of this on the bulkstat algorithm&lt;br /&gt;
has not been determined yet.&lt;br /&gt;
&lt;br /&gt;
One of the issues we need to consider with this background inactivation is that&lt;br /&gt;
we will be able to defer a large quantity of inactivation transactions so we are&lt;br /&gt;
going to need to be careful about how much we allow to be queued. Simple queue&lt;br /&gt;
depth throttling should be all that is needed to keep this under control.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Reclaim Optimizations ==&lt;br /&gt;
&lt;br /&gt;
Tracking inodes for reclaim in radix tree: Done&lt;br /&gt;
Using RCU for radix tree reclaim walks: Done&lt;br /&gt;
Non-blocking background reclaim: Done&lt;br /&gt;
Parallelised shrinker based reclaim: Done&lt;br /&gt;
&lt;br /&gt;
Now that we have efficient unlink, we&#039;ve got to handle the reclaim of all the&lt;br /&gt;
inodes that are now dead or simply not referenced. For inodes that are dirty,&lt;br /&gt;
we need to write them out to clean them. For inodes that are clean and not&lt;br /&gt;
unlinked, we need to compress them down for more compact storage. This involves&lt;br /&gt;
some CPU overhead, but it is worth noting that reclaiming of clean inodes&lt;br /&gt;
typically only occurs when we are under memory pressure.&lt;br /&gt;
&lt;br /&gt;
By compressing the XFS inode in this case, we are effectively reducing the&lt;br /&gt;
memory usage of the inode rather than freeing it directly. If we then get&lt;br /&gt;
another operation on that inode (e.g. the working set is slightly larger than&lt;br /&gt;
can be held in linux+XFS inode pairs, we avoid having to read the inode off&lt;br /&gt;
disk again - it simply gets uncompressed out of the cache. In essence we use&lt;br /&gt;
the compressed inode cache as an exclusive second level cache - it has higher&lt;br /&gt;
density than the primary cache and higher load latency and CPU overhead,&lt;br /&gt;
but it still avoids I/O in exactly the same manner as the primary cache.&lt;br /&gt;
&lt;br /&gt;
We cannot allow unrestricted build-up of reclaimable inodes - the memory they&lt;br /&gt;
consume will be large, so we should be aiming to compress reclaimable inodes as&lt;br /&gt;
soon as they are clean.  This will prevent buildup of memory consuming&lt;br /&gt;
uncompressed inodes that are not likely to be referenced again immediately.&lt;br /&gt;
&lt;br /&gt;
This clean inode reclaimation process can be accelerated by triggering reclaim&lt;br /&gt;
on inode I/O completion. If the inode is clean and reclaimable we should&lt;br /&gt;
trigger immediate reclaim processing of that inode.  This will mean that&lt;br /&gt;
reclaim of newly cleaned inodes will not get held up behind reclaim of dirty&lt;br /&gt;
inodes.&lt;br /&gt;
&lt;br /&gt;
For inodes that are unlinked, we can simply free them in reclaim as theƦ&lt;br /&gt;
are no longer in use. We don&#039;t want to poison the compressed cache with&lt;br /&gt;
unlinked inodes, nor do we need to because we can allocate new inodes&lt;br /&gt;
without incurring I/O.&lt;br /&gt;
&lt;br /&gt;
Still, we may end up with lots of inodes queued for reclaim. We may need&lt;br /&gt;
to implement a throttle mechanism to slow down the rate at which inodes&lt;br /&gt;
are queued for reclaimation in the situation where the reclaim process&lt;br /&gt;
is not able to keep up. It should be noted that if we parallelise inode&lt;br /&gt;
writeback we should also be able to parallelise inode reclaim via&lt;br /&gt;
the same mechanism, so the need for throttling may relatively low&lt;br /&gt;
if we can have multiple inodes under reclaim at once.&lt;br /&gt;
&lt;br /&gt;
It should be noted that complexity is exposed by interactions with concurrent&lt;br /&gt;
lookups, especially if we move to RCU locking on the radix tree. Firstly, we&lt;br /&gt;
need to be able to do an atomic swap of the compressed inode for the&lt;br /&gt;
uncompressed inode in the radix tree (and vice versa), to be able to tell them&lt;br /&gt;
apart (magic #), and to have atomic reference counts to ensure we can avoid use&lt;br /&gt;
after free situations when lookups race with compression or freeing.&lt;br /&gt;
&lt;br /&gt;
Secondly, with the complex unlink/reclaim interactions we will need to be&lt;br /&gt;
careful to detect inodes in the process of reclaim - the lookupp process&lt;br /&gt;
will need to do different things depending on the state of reclaim. Indeed,&lt;br /&gt;
we will need to be able to cancel reclaim of an unlinked inode if we try&lt;br /&gt;
to allocate it before it has been fully unlinked or reclaimed. The same&lt;br /&gt;
can be said for an inode in the process of being compressed - if we get&lt;br /&gt;
a lookup during the compression process, we want to return the existing&lt;br /&gt;
inode, not have to wait, re-allocate and uncompress it again. These&lt;br /&gt;
are all solvable issues - they just add complexity.&lt;br /&gt;
&lt;br /&gt;
== Accelerated Reclaim of buftarg Page Cache for Inodes ==&lt;br /&gt;
----------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Per-buftarg buffer LRU reclaim: Done&lt;br /&gt;
&lt;br /&gt;
Per-buftarg shrinker: Done&lt;br /&gt;
&lt;br /&gt;
Per-buffer type reclaim prioritisation: Done&lt;br /&gt;
&lt;br /&gt;
For single use inodes or even read-only inodes, we read them in, use them, then&lt;br /&gt;
reclaim them. With the compressed cache, they&#039;ll get compressed and live a lot&lt;br /&gt;
longer in memory. However, we also will have the inode cluster buffer pages&lt;br /&gt;
sitting in memory for some length of time after the inode was read in. This can&lt;br /&gt;
consume a large amount of memory that will never be used again, and does not&lt;br /&gt;
get reclaimed until they are purged from the LRU by the VM.  It would be&lt;br /&gt;
advantageous to accelerate the reclaim of these pages so that they do not build&lt;br /&gt;
up unneccessarily.&lt;br /&gt;
&lt;br /&gt;
A better method would appear to be to leverage the delayed read queue&lt;br /&gt;
mechanism. This delayed read queue pins read buffers for a short period of&lt;br /&gt;
time, and then if they have not been referenced they get torn down.  If, as&lt;br /&gt;
part of this delayed read buffer teardown procedure we all free the backing&lt;br /&gt;
pages completely, we acheive the exact same result as having our own LRUs to&lt;br /&gt;
manage the page cache. This seems much simpler and a much more holistic&lt;br /&gt;
approach to solving the problem than implementing page LRUs.&lt;br /&gt;
&lt;br /&gt;
== Killing Bufferheads (a.k.a &amp;quot;Die, buggerheads, Die!&amp;quot;) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[This is not strictly about inode caching, but doesn&#039;t fit into&lt;br /&gt;
other areas of development as closely as it does to inode caching&lt;br /&gt;
optimisations.]&lt;br /&gt;
&lt;br /&gt;
XFS is extent based. The Linux page cache is block based. Hence for&lt;br /&gt;
every cached page in memory, we have to attach a structure for mapping&lt;br /&gt;
the blocks on that page back to to the on-disk location. In XFs, we also&lt;br /&gt;
use this to hold state for delayed allocation and unwritten extent blocks&lt;br /&gt;
so the generic code can do the right thing when necessary. We also&lt;br /&gt;
use it to avoid extent lookups at various times within the XFS I/O&lt;br /&gt;
path.&lt;br /&gt;
&lt;br /&gt;
However, this has a massive cost. While XFS might represent the&lt;br /&gt;
disk mapping of a 1GB extent in 24 bytes of memory, the page cache&lt;br /&gt;
requires 262,144 bufferheads (assuming 4k block size) to represent the&lt;br /&gt;
same mapping. That&#039;s roughly 14MB of memory neededtoo represent that.&lt;br /&gt;
&lt;br /&gt;
Chris Mason wrote an extent map representation for page cache state&lt;br /&gt;
and mappings for BTRFS; that code is mostly generic and could be&lt;br /&gt;
adapted to XFS. This would allow us to hold all the page cache state&lt;br /&gt;
in extent format and greatly reduce the memory overhead that it currently&lt;br /&gt;
has. The tradeoff is increased CPU overhead due to tree lookups where&lt;br /&gt;
structure lookups currently are used. Still, this has much lower&lt;br /&gt;
overhead than xfs_bmapi() based lookups, so the penalty is going to&lt;br /&gt;
be lower than if we did these lookups right now.&lt;br /&gt;
&lt;br /&gt;
If we make this change, we would then have three levels of extent&lt;br /&gt;
caching:&lt;br /&gt;
&lt;br /&gt;
	- the BMBT buffers&lt;br /&gt;
	- the XFS incore inode extent tree (iext*)&lt;br /&gt;
	- the page cache extent map tree&lt;br /&gt;
&lt;br /&gt;
Effectively, the XFS incore inode extent tree becomes redundant - all&lt;br /&gt;
the extent state it holds can be moved to the generic page cache tree&lt;br /&gt;
and we can do all our incore operations there. Our logging of changes&lt;br /&gt;
is based on the BMBT buffers, so getting rid of the iext layer would&lt;br /&gt;
not impact the transaction subsystem at all.&lt;br /&gt;
&lt;br /&gt;
Such integration with the generic code will also allow development&lt;br /&gt;
of generic writeback routines for delayed allocation, unwritten&lt;br /&gt;
extents, etc that are not specific to a given filesystem.&lt;br /&gt;
&lt;br /&gt;
== Demand Paging of Large Inode Extent Maps ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Currently the inode extent map is pinned  in memory until the inode is&lt;br /&gt;
reclaimed. Hence an inode with millions of extents will pin a large&lt;br /&gt;
amount of memory and this can cause serious issues in low memory&lt;br /&gt;
situations. Ideally we would like to be able to page the extent&lt;br /&gt;
map in and out once they get to a certain size to avoid this&lt;br /&gt;
problem. This feature requires more investigation before an overall&lt;br /&gt;
approach can be detailed here.&lt;br /&gt;
&lt;br /&gt;
It should be noted that if we move to an extent-based page cache mapping&lt;br /&gt;
tree, the associated extent state tree can be used to track sparse&lt;br /&gt;
regions. That is, regions of the extent map that are not in memory&lt;br /&gt;
can be easily represented and acceesses to an unread region can then&lt;br /&gt;
be used to trigger demand loading.&lt;br /&gt;
&lt;br /&gt;
== Food For Thought (Crazy Ideas) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If we are not using inode buffers for logging changes to inodes, we should&lt;br /&gt;
consider whether we need them at all. What benefit do the buffers bring us when&lt;br /&gt;
all we will use them for is read or write I/O?  Would it be better to go&lt;br /&gt;
straight to the buftarg page cache and do page based I/O via submit_bio()?&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=Improving_inode_Caching&amp;diff=2131</id>
		<title>Improving inode Caching</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=Improving_inode_Caching&amp;diff=2131"/>
		<updated>2010-12-23T03:50:37Z</updated>

		<summary type="html">&lt;p&gt;Dgc: /* Accelerated Reclaim of buftarg Page Cache for Inodes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Future Directions for XFS&lt;br /&gt;
&lt;br /&gt;
== Improving Inode Caching and Operation in XFS ==&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Thousand foot view:&lt;br /&gt;
&lt;br /&gt;
We want to drive inode lookup in a manner that is as parallel, scalable and low&lt;br /&gt;
overhead as possible. This means efficient indexing, lowering memory&lt;br /&gt;
consumption, simplifying the caching heirachy, removing duplication and&lt;br /&gt;
reducing/removing lock traffic.&lt;br /&gt;
&lt;br /&gt;
In addition, we want to provide a good foundation for simplifying inode I/O,&lt;br /&gt;
improving writeback clustering, preventing RMW of inode buffers under memory&lt;br /&gt;
pressure, reducing creation and deletion overhead and removing writeback of&lt;br /&gt;
unlogged changes completely.&lt;br /&gt;
&lt;br /&gt;
There are a variety of features in disconnected trees and patch sets that need&lt;br /&gt;
to be combined to acheive this - the basic structure needed to implement this is&lt;br /&gt;
already in mainline and that is the radix tree inode indexing.  Further&lt;br /&gt;
improvements are going to be based around this structure and using it&lt;br /&gt;
effectively to avoid needing other indexing mechanisms.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Discussion:&lt;br /&gt;
&lt;br /&gt;
== Combining XFS and VFS inodes ==&lt;br /&gt;
----------------------------&lt;br /&gt;
&lt;br /&gt;
Status: Done (October 2008)&lt;br /&gt;
&lt;br /&gt;
== Compressed Inode Cache ==&lt;br /&gt;
-----------------------------&lt;br /&gt;
&lt;br /&gt;
The XFs inode cache uses a lot of memory. We can avoid this problem by making&lt;br /&gt;
use of the compressed inode cache - only the active inodes are held in a&lt;br /&gt;
non-compressed form, hence most inodes will end up being cached in compressed&lt;br /&gt;
form rather than in the XFS/linux inode form.  The compressed form can reduce&lt;br /&gt;
the cached inode footprint to 200-300 bytes per inode instead of 1-1.1k that&lt;br /&gt;
they currently take on a 64bit system. Hence by moving to a compressed cache we&lt;br /&gt;
can greatly increase the number of inodes cached in a given amount of memory&lt;br /&gt;
which more that offsets any comparitive increase we will see from inodes in&lt;br /&gt;
reclaim. the compressed cache should really have a LRU and a shrinker as well&lt;br /&gt;
so that memory pressure will slowly trim it as memory demands occur. [Note:&lt;br /&gt;
this compressed cache is discussed further later on in the reclaim context.]&lt;br /&gt;
&lt;br /&gt;
== Fixed Inode Cache Size ==&lt;br /&gt;
&lt;br /&gt;
It is worth noting that for embedded systems and appliances it may be worth while allowing&lt;br /&gt;
the size of the caches to be fixed. Also, to prevent memory fragmentation&lt;br /&gt;
problems, we could simply allocate that memory to the compressed cache slab.&lt;br /&gt;
In effect, this would become a &#039;static slab&#039; in that it has a bound maximum&lt;br /&gt;
size and never frees and memory. When the cache is full, we reclaim an&lt;br /&gt;
object out of it for reuse - this could be done by triggering the shrinker&lt;br /&gt;
to reclaim from the LRU. This would prevent the compressed inode cache from&lt;br /&gt;
consuming excessive amounts of memory in tightly constrained evironments.&lt;br /&gt;
Such an extension to the slab caches does not look difficult to implement,&lt;br /&gt;
and would allow such customisation with minimal deviation from mainline code.&lt;br /&gt;
&lt;br /&gt;
== Bypassing the Linux Inode Cache ==&lt;br /&gt;
&lt;br /&gt;
Lookups: Done (October 2008)&lt;br /&gt;
&lt;br /&gt;
Tracking dirty inodes: Done&lt;br /&gt;
&lt;br /&gt;
Writeback of dirty inodes: Done&lt;br /&gt;
&lt;br /&gt;
Writeback of dirty pages: still executed the by VFS&lt;br /&gt;
&lt;br /&gt;
Now that we can track dirty inodes ourselves, we can pretty much isolate&lt;br /&gt;
writeback of both data and inodes from the generic pdflush code. If we add a&lt;br /&gt;
hook high up in the pdflush path that simply passes us a writeback control&lt;br /&gt;
structure with the current writeback guidelines, we can do writeback within&lt;br /&gt;
those guidelines in the most optimal fashion for XFS.&lt;br /&gt;
&lt;br /&gt;
== Avoiding the Generic pdflush Code ==&lt;br /&gt;
&lt;br /&gt;
Writeback of inodes via AIL: Done&lt;br /&gt;
&lt;br /&gt;
For pdflush driven writeback, we only want to write back data; all other inode&lt;br /&gt;
writeback should be driven from the AIL (our time ordered dirty metadata list)&lt;br /&gt;
or xfssyncd in a manner that is most optimal for XFS.&lt;br /&gt;
&lt;br /&gt;
Furthermore, if we implement our own pdflush method, we can parallelise it in&lt;br /&gt;
several ways. We can ensure that each filesystem has it&#039;s own flush thread or&lt;br /&gt;
thread pool, we can have a thread pool shared by all filesystems (like pdflush&lt;br /&gt;
currently operates), we can have a flush thread per inode radix tree, and so&lt;br /&gt;
one. The method of paralleisation is open for interpretation, but enabling&lt;br /&gt;
multiple flush threads to operate on a single filesystem is one of the necessary&lt;br /&gt;
requirements to avoid data writeback (and hence delayed allocation) being&lt;br /&gt;
limited to the throughput of a single CPU per filesystem.&lt;br /&gt;
&lt;br /&gt;
== Improving Inode Writeback == &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To optimise inode writeback, we really need to reduce the impact of inode&lt;br /&gt;
buffer read-modify-write cycles. XFS is capable of caching far more inodes in&lt;br /&gt;
memory than it has buffer space available for, so RMW cycles during inode&lt;br /&gt;
writeback under memory pressure are quite common. Firstly, we want to avoid&lt;br /&gt;
blocking pdflush at all costs.  Secondly, we want to issue as much localised&lt;br /&gt;
readahead as possible in ascending offset order to allow both elevator merging&lt;br /&gt;
of readahead and as little seeking as possible. Finally, we want to issue all&lt;br /&gt;
the write cycles as close together as possible to allow the same elevator and&lt;br /&gt;
I/O optimisations to take place.&lt;br /&gt;
&lt;br /&gt;
To do this, firstly we need the non-blocking inode flush semantics to issue&lt;br /&gt;
readahead on buffers that are not up-to-date rather than reading them&lt;br /&gt;
synchronously. Inode writeback already has the interface to handle inodes that&lt;br /&gt;
weren&#039;t flushed - we return EAGAIN from xfs_iflush() and the higher inode&lt;br /&gt;
writeback layers handle this appropriately. It would be easy to add another&lt;br /&gt;
flag to pass down to the buffer layer to say &#039;issue but don&#039;t wait for any&lt;br /&gt;
read&#039;. If we use a radix tree traversal to issue readahead in such a manner,&lt;br /&gt;
we&#039;ll get ascending offset readahead being issued.&lt;br /&gt;
&lt;br /&gt;
One problem with this is that we can issue too much readahead and thrash the&lt;br /&gt;
cache. A possible solution to this is to make the readahead a &#039;delayed read&#039;&lt;br /&gt;
and on I/o completion add it to a queue that holds a reference on the buffer.&lt;br /&gt;
If a followup read occurs soon after, we remove it from the queue and drop that&lt;br /&gt;
reference. This prevents the buffer from being reclaimed in betwen the&lt;br /&gt;
readahead completing and the real read being issued. We should also issue this&lt;br /&gt;
delayed read on buffers that are in the cache so that they don&#039;t get reclaimed&lt;br /&gt;
to make room for the readahead.&lt;br /&gt;
&lt;br /&gt;
To prevent buildup of delayed read buffers, we can periodically purge them -&lt;br /&gt;
those that are older than a given age (say 5 seconds) can be removed from the&lt;br /&gt;
list and their reference dropped. This will free the buffer and allow it&#039;s&lt;br /&gt;
pages to be reclaimed.&lt;br /&gt;
&lt;br /&gt;
Once we have done the readahead pass, we can then do a modify and writeback&lt;br /&gt;
pass over all the inodes, knowing that there will be no read cycles to delay&lt;br /&gt;
this step. Once again, a radix tree traversal gives us ascending order&lt;br /&gt;
writeback and hence the modified buffers we send to the device will be in&lt;br /&gt;
optimal order for merging and minimal seek overhead.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Contiguous Inode Allocation ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To make optimal use of the radix tree cache and enable wide-scale clustering of&lt;br /&gt;
inode writeback across multiple clusters, we really need to ensure that inode&lt;br /&gt;
allocation occurs in large contiguous chunks on disk. Right now we only&lt;br /&gt;
allocate chunks of 64 inodes at a time; ideally we want to allocate a stripe&lt;br /&gt;
unit (or multiple of) full of inodes at a time. This would allow inode&lt;br /&gt;
writeback clustering to do full stripe writes to the underlying RAID if there&lt;br /&gt;
are dirty inodes spanning the entire stripe unit.&lt;br /&gt;
&lt;br /&gt;
The problem with doing this is that we don&#039;t want to introduce the latency of&lt;br /&gt;
creating megabytes of inodes when only one is needed for the current operation.&lt;br /&gt;
Hence we need to push the inode creation into a background thread and use that&lt;br /&gt;
to create contiguous inode chunks asynchronously. This moves the actual on-disk&lt;br /&gt;
allocation of inodes out of the normal create path; it should always be able to&lt;br /&gt;
find a free inode without doing on disk allocation. This will simplify the&lt;br /&gt;
create path by removing the allocate-on-disk-then-retry-the-create double&lt;br /&gt;
transaction that currently occurs.&lt;br /&gt;
&lt;br /&gt;
As an aside, we could preallocate a small amount of inodes in each AG (10-20MB&lt;br /&gt;
of inodes per AG?) without impacting mkfs time too greatly. This would allow&lt;br /&gt;
the filesystem to be used immediately on the first mount without triggering&lt;br /&gt;
lots of background allocation. This could alsobe done after the first mount&lt;br /&gt;
occurs, but that could interfere with typical benchmarking situations. Another&lt;br /&gt;
good reason for this preallocation is that it will help reduce xfs_repair&lt;br /&gt;
runtime for most common filesystem usages.&lt;br /&gt;
&lt;br /&gt;
One of the issues that the background create will cause is a substantial amount&lt;br /&gt;
of log traffic - every inode buffer initialised will be logged in whole. Hence&lt;br /&gt;
if we create a megabyte of inodes, we&#039;ll be causing a megabyte of log traffic&lt;br /&gt;
just for the inode buffers we&#039;ve initialised.  This is relatively simple to fix&lt;br /&gt;
- we don&#039;t log the buffer, we just log the fact that we need to initialise&lt;br /&gt;
inodes in a given range.  In recovery, when we see this transaction, then we&lt;br /&gt;
build the buffers, initialise them and write them out. Hence, we don&#039;t need to&lt;br /&gt;
log the buffers used to initialise the inodes.&lt;br /&gt;
&lt;br /&gt;
Also, we can use the background allocations to keep track of recently allocated&lt;br /&gt;
inode regions in the per-ag. Using that information to select the next inode to&lt;br /&gt;
be used rather than requiring btree searches on every create will greatly reduce&lt;br /&gt;
the CPU overhead of workloads that create lots of new inodes. It is not clear&lt;br /&gt;
whether a single background thread will be able to allocate enough inodes&lt;br /&gt;
to keep up with demand from the rest of the system - we may need multiple&lt;br /&gt;
threads for large configurations.&lt;br /&gt;
&lt;br /&gt;
== Single Block Inode Allocation ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
One of the big problems we have withe filesystems that are approaching&lt;br /&gt;
full is that it can be hard to find a large enough extent to hold 64 inodes.&lt;br /&gt;
We&#039;ve had ENOSPC errors on inode allocation reported on filesystems that&lt;br /&gt;
are only 85% full. This is a sign of free space fragmentation, and it&lt;br /&gt;
prevents inode allocation from succeeding. We could (and should) write&lt;br /&gt;
a free space defragmenter, but that does not solve the problem - it&#039;s&lt;br /&gt;
reactive, not preventative.&lt;br /&gt;
&lt;br /&gt;
The main problem we have is that XFS uses inode chunk size and alignment&lt;br /&gt;
to optimise inode number to disk location conversion. That is, the conversion&lt;br /&gt;
becomes a single set of shifts and masks instead of an AGI btree lookup.&lt;br /&gt;
This optimisation substantially reduces the CPU and I/O overhead of&lt;br /&gt;
inode lookups, but it does limit our flexibility. If we break the&lt;br /&gt;
alignment restriction, every lookup has to go back to a btree search.&lt;br /&gt;
Hence we really want to avoid breaking chunk alignment and size&lt;br /&gt;
rules.&lt;br /&gt;
&lt;br /&gt;
An approach to avoiding violation of this rule is to be able to determine which&lt;br /&gt;
index to look up when parsing the inode number. For example, we could use the&lt;br /&gt;
high bit of the inode number to indicate that it is located in a non-aligned&lt;br /&gt;
inode chunk and hence needs to be looked up in the btree. This would avoid&lt;br /&gt;
the lookup penalty for correctly aligned inode chunks.&lt;br /&gt;
&lt;br /&gt;
If we then redefine the meaning of the contents of the AGI btree record for&lt;br /&gt;
such inode chunks, we do not need a new index to keep these in. Effectively,&lt;br /&gt;
we need to add a bitmask to the record to indicate which blocks inside&lt;br /&gt;
the chunk can actually contain inodes. We still use aligned/sized records,&lt;br /&gt;
but mask out the sections that we are not allowed to allocate inodes in.&lt;br /&gt;
Effectively, this would allow sparse inode chunks. There may be limitations&lt;br /&gt;
on the resolution of sparseness depending on inode size and block size,&lt;br /&gt;
but for the common cases of 4k block size and 256 or 512 byte inodes I&lt;br /&gt;
think we can run a fully sparse mapping for each inode chunk.&lt;br /&gt;
&lt;br /&gt;
This would allow us to allocate inode extents of any alignment and size&lt;br /&gt;
that fits *inside* the existing alignment/size limitations. That is,&lt;br /&gt;
a single extent allocation could not span two btree records, but can&lt;br /&gt;
lie anywhere inside a single record. It also means that we can do&lt;br /&gt;
multiple extent allocations within one btree record to make optimal&lt;br /&gt;
use of the fragmented free space.&lt;br /&gt;
&lt;br /&gt;
It should be noted that this will probably have impact on some of the&lt;br /&gt;
inode cluster buffer mapping and clustering algorithms. It is not clear&lt;br /&gt;
exactly what impact yet, but certainly write clustering will be affected.&lt;br /&gt;
Fortunately we&#039;ll be able to detect the inodes that will have this problem&lt;br /&gt;
by the high bit in the inode number.&lt;br /&gt;
&lt;br /&gt;
== Inode Unlink ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If we turn to look at unlink and reclaim interactions, there are a few&lt;br /&gt;
optimisations that can be made.  Firstly, we don&#039;t need to do inode inactivation&lt;br /&gt;
in reclaim threads - these transactions can easily be pushed to a background&lt;br /&gt;
thread. This means that xfs_inactive would be little more than a vmtruncate()&lt;br /&gt;
call and queuing to a workqueue. This will substantially speed up the processing&lt;br /&gt;
of prune_icache() - we&#039;ll get inodes moved into reclaim much faster than we do&lt;br /&gt;
right now.&lt;br /&gt;
&lt;br /&gt;
This will have a noticable effect, though. When inodes are unlinked the space&lt;br /&gt;
consumed by those inodes may not be immediately freed - it will be returned as&lt;br /&gt;
the inodes are processed through the reclaim threads. This means that userspace&lt;br /&gt;
monitoring tools such as &#039;df&#039; may not immediately reflect the result of a&lt;br /&gt;
completed unlink operation. This will be a user visible change in behaviour,&lt;br /&gt;
though in most cases should not affect anyone and for those that it does affect&lt;br /&gt;
a &#039;sync&#039; should be sufficient to wait for the space to be returned.&lt;br /&gt;
&lt;br /&gt;
Now that inodes to be unlinked are out of general circulation, we can make the&lt;br /&gt;
unlinked path more complex. It is desirable to move the unlinked list from the&lt;br /&gt;
inode buffer to the inode core, but that has locking implications for incore&lt;br /&gt;
unlinked. Hence we really need background thread processing to enable this to&lt;br /&gt;
work (i.e. being able to requeue inodes for later processing). To ensure that&lt;br /&gt;
to overhead of this work is not a limiting factor, we will probably need&lt;br /&gt;
multiple workqueue processing threads for this.&lt;br /&gt;
&lt;br /&gt;
Moving the logging to the inode core enables two things - it allows us to keep&lt;br /&gt;
an in-memory copy of the unlinked list off the perag and that allows us to remove&lt;br /&gt;
xfs_inotobp(). The in-memory unlinked list means we don&#039;t have to read and&lt;br /&gt;
traverse the buffers every time we need to find the previous buffer to remove an&lt;br /&gt;
inode from the list, but it does mean we have to take the inode lock. If the&lt;br /&gt;
previous inode is locked, then we can&#039;t remove the inode from the unlinked list&lt;br /&gt;
so we must requeue it for this to occur at a later time.&lt;br /&gt;
&lt;br /&gt;
Combined with the changes to inode create, we effectively will only use the&lt;br /&gt;
inode buffer in the transaction subsystem for marking the region stale when&lt;br /&gt;
freeing an inode chunk from disk (i.e. the default noikeep configuration). If&lt;br /&gt;
we are using large inode allocation, we don&#039;t want to be freeing random inode&lt;br /&gt;
chunks - this will just leave us with fragmented inode regions and undo all the&lt;br /&gt;
good work that was done originally.&lt;br /&gt;
&lt;br /&gt;
To avoid this, we should not be freeing inode chunks as soon as they no longer&lt;br /&gt;
have any empty inodes in them. We should periodically scan the AGI btree&lt;br /&gt;
looking for contiguous chunks that have no inodes allocated in them, and then&lt;br /&gt;
freeing the large contiguous regions we find in one go. It is likely this can&lt;br /&gt;
be done in a single transaction; it&#039;s one extent to be freed, along with a&lt;br /&gt;
contiguous set of records to be removed from the AGI btree so should not&lt;br /&gt;
require logging much at all. Also, the background scanning could be triggered&lt;br /&gt;
by a number of different events - low space in an AG, a large number of free&lt;br /&gt;
inodes in an AG, etc - as it doesn&#039;t need to be done frequently. As a result&lt;br /&gt;
of the lack of frequency that this needs to be done, it can probably be&lt;br /&gt;
handled by a single thread or delayed workqueue.&lt;br /&gt;
&lt;br /&gt;
Further optimisations are possible here - if we rule that the AGI btree is the&lt;br /&gt;
sole place that inodes are marked free or in-use (with the exception of&lt;br /&gt;
unlinked inodes attached to the AGI lists), then we can avoid the need to&lt;br /&gt;
write back unlinked inodes or read newly created inodes from disk.  This would&lt;br /&gt;
require all inodes to effectively use a random generation number assigned at&lt;br /&gt;
create time as we would not be reading it from disk - writing/reading the current&lt;br /&gt;
generation number appears to be the only real reason for doing this I/O. This&lt;br /&gt;
would require extra checks to determine if an inode is unlinked - we&lt;br /&gt;
need to do an imap lookup rather than reading it and then checking it is&lt;br /&gt;
valid if it is not already in memory. Avoiding the I/O, however, will greatly speed&lt;br /&gt;
up create and remove workloads. Note: the impact of this on the bulkstat algorithm&lt;br /&gt;
has not been determined yet.&lt;br /&gt;
&lt;br /&gt;
One of the issues we need to consider with this background inactivation is that&lt;br /&gt;
we will be able to defer a large quantity of inactivation transactions so we are&lt;br /&gt;
going to need to be careful about how much we allow to be queued. Simple queue&lt;br /&gt;
depth throttling should be all that is needed to keep this under control.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Reclaim Optimizations ==&lt;br /&gt;
&lt;br /&gt;
Tracking inodes for reclaim in radix tree: Done&lt;br /&gt;
Using RCU for radix tree reclaim walks: Done&lt;br /&gt;
Non-blocking background reclaim: Done&lt;br /&gt;
Parallelised shrinker based reclaim: Done&lt;br /&gt;
&lt;br /&gt;
Now that we have efficient unlink, we&#039;ve got to handle the reclaim of all the&lt;br /&gt;
inodes that are now dead or simply not referenced. For inodes that are dirty,&lt;br /&gt;
we need to write them out to clean them. For inodes that are clean and not&lt;br /&gt;
unlinked, we need to compress them down for more compact storage. This involves&lt;br /&gt;
some CPU overhead, but it is worth noting that reclaiming of clean inodes&lt;br /&gt;
typically only occurs when we are under memory pressure.&lt;br /&gt;
&lt;br /&gt;
By compressing the XFS inode in this case, we are effectively reducing the&lt;br /&gt;
memory usage of the inode rather than freeing it directly. If we then get&lt;br /&gt;
another operation on that inode (e.g. the working set is slightly larger than&lt;br /&gt;
can be held in linux+XFS inode pairs, we avoid having to read the inode off&lt;br /&gt;
disk again - it simply gets uncompressed out of the cache. In essence we use&lt;br /&gt;
the compressed inode cache as an exclusive second level cache - it has higher&lt;br /&gt;
density than the primary cache and higher load latency and CPU overhead,&lt;br /&gt;
but it still avoids I/O in exactly the same manner as the primary cache.&lt;br /&gt;
&lt;br /&gt;
We cannot allow unrestricted build-up of reclaimable inodes - the memory they&lt;br /&gt;
consume will be large, so we should be aiming to compress reclaimable inodes as&lt;br /&gt;
soon as they are clean.  This will prevent buildup of memory consuming&lt;br /&gt;
uncompressed inodes that are not likely to be referenced again immediately.&lt;br /&gt;
&lt;br /&gt;
This clean inode reclaimation process can be accelerated by triggering reclaim&lt;br /&gt;
on inode I/O completion. If the inode is clean and reclaimable we should&lt;br /&gt;
trigger immediate reclaim processing of that inode.  This will mean that&lt;br /&gt;
reclaim of newly cleaned inodes will not get held up behind reclaim of dirty&lt;br /&gt;
inodes.&lt;br /&gt;
&lt;br /&gt;
For inodes that are unlinked, we can simply free them in reclaim as theƦ&lt;br /&gt;
are no longer in use. We don&#039;t want to poison the compressed cache with&lt;br /&gt;
unlinked inodes, nor do we need to because we can allocate new inodes&lt;br /&gt;
without incurring I/O.&lt;br /&gt;
&lt;br /&gt;
Still, we may end up with lots of inodes queued for reclaim. We may need&lt;br /&gt;
to implement a throttle mechanism to slow down the rate at which inodes&lt;br /&gt;
are queued for reclaimation in the situation where the reclaim process&lt;br /&gt;
is not able to keep up. It should be noted that if we parallelise inode&lt;br /&gt;
writeback we should also be able to parallelise inode reclaim via&lt;br /&gt;
the same mechanism, so the need for throttling may relatively low&lt;br /&gt;
if we can have multiple inodes under reclaim at once.&lt;br /&gt;
&lt;br /&gt;
It should be noted that complexity is exposed by interactions with concurrent&lt;br /&gt;
lookups, especially if we move to RCU locking on the radix tree. Firstly, we&lt;br /&gt;
need to be able to do an atomic swap of the compressed inode for the&lt;br /&gt;
uncompressed inode in the radix tree (and vice versa), to be able to tell them&lt;br /&gt;
apart (magic #), and to have atomic reference counts to ensure we can avoid use&lt;br /&gt;
after free situations when lookups race with compression or freeing.&lt;br /&gt;
&lt;br /&gt;
Secondly, with the complex unlink/reclaim interactions we will need to be&lt;br /&gt;
careful to detect inodes in the process of reclaim - the lookupp process&lt;br /&gt;
will need to do different things depending on the state of reclaim. Indeed,&lt;br /&gt;
we will need to be able to cancel reclaim of an unlinked inode if we try&lt;br /&gt;
to allocate it before it has been fully unlinked or reclaimed. The same&lt;br /&gt;
can be said for an inode in the process of being compressed - if we get&lt;br /&gt;
a lookup during the compression process, we want to return the existing&lt;br /&gt;
inode, not have to wait, re-allocate and uncompress it again. These&lt;br /&gt;
are all solvable issues - they just add complexity.&lt;br /&gt;
&lt;br /&gt;
== Accelerated Reclaim of buftarg Page Cache for Inodes ==&lt;br /&gt;
----------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Per-buftarg buffer LRU reclaim: Done&lt;br /&gt;
Per-buftarg shrinker: Done&lt;br /&gt;
Per-buffer type reclaim prioritisation: Done&lt;br /&gt;
&lt;br /&gt;
For single use inodes or even read-only inodes, we read them in, use them, then&lt;br /&gt;
reclaim them. With the compressed cache, they&#039;ll get compressed and live a lot&lt;br /&gt;
longer in memory. However, we also will have the inode cluster buffer pages&lt;br /&gt;
sitting in memory for some length of time after the inode was read in. This can&lt;br /&gt;
consume a large amount of memory that will never be used again, and does not&lt;br /&gt;
get reclaimed until they are purged from the LRU by the VM.  It would be&lt;br /&gt;
advantageous to accelerate the reclaim of these pages so that they do not build&lt;br /&gt;
up unneccessarily.&lt;br /&gt;
&lt;br /&gt;
A better method would appear to be to leverage the delayed read queue&lt;br /&gt;
mechanism. This delayed read queue pins read buffers for a short period of&lt;br /&gt;
time, and then if they have not been referenced they get torn down.  If, as&lt;br /&gt;
part of this delayed read buffer teardown procedure we all free the backing&lt;br /&gt;
pages completely, we acheive the exact same result as having our own LRUs to&lt;br /&gt;
manage the page cache. This seems much simpler and a much more holistic&lt;br /&gt;
approach to solving the problem than implementing page LRUs.&lt;br /&gt;
&lt;br /&gt;
== Killing Bufferheads (a.k.a &amp;quot;Die, buggerheads, Die!&amp;quot;) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[This is not strictly about inode caching, but doesn&#039;t fit into&lt;br /&gt;
other areas of development as closely as it does to inode caching&lt;br /&gt;
optimisations.]&lt;br /&gt;
&lt;br /&gt;
XFS is extent based. The Linux page cache is block based. Hence for&lt;br /&gt;
every cached page in memory, we have to attach a structure for mapping&lt;br /&gt;
the blocks on that page back to to the on-disk location. In XFs, we also&lt;br /&gt;
use this to hold state for delayed allocation and unwritten extent blocks&lt;br /&gt;
so the generic code can do the right thing when necessary. We also&lt;br /&gt;
use it to avoid extent lookups at various times within the XFS I/O&lt;br /&gt;
path.&lt;br /&gt;
&lt;br /&gt;
However, this has a massive cost. While XFS might represent the&lt;br /&gt;
disk mapping of a 1GB extent in 24 bytes of memory, the page cache&lt;br /&gt;
requires 262,144 bufferheads (assuming 4k block size) to represent the&lt;br /&gt;
same mapping. That&#039;s roughly 14MB of memory neededtoo represent that.&lt;br /&gt;
&lt;br /&gt;
Chris Mason wrote an extent map representation for page cache state&lt;br /&gt;
and mappings for BTRFS; that code is mostly generic and could be&lt;br /&gt;
adapted to XFS. This would allow us to hold all the page cache state&lt;br /&gt;
in extent format and greatly reduce the memory overhead that it currently&lt;br /&gt;
has. The tradeoff is increased CPU overhead due to tree lookups where&lt;br /&gt;
structure lookups currently are used. Still, this has much lower&lt;br /&gt;
overhead than xfs_bmapi() based lookups, so the penalty is going to&lt;br /&gt;
be lower than if we did these lookups right now.&lt;br /&gt;
&lt;br /&gt;
If we make this change, we would then have three levels of extent&lt;br /&gt;
caching:&lt;br /&gt;
&lt;br /&gt;
	- the BMBT buffers&lt;br /&gt;
	- the XFS incore inode extent tree (iext*)&lt;br /&gt;
	- the page cache extent map tree&lt;br /&gt;
&lt;br /&gt;
Effectively, the XFS incore inode extent tree becomes redundant - all&lt;br /&gt;
the extent state it holds can be moved to the generic page cache tree&lt;br /&gt;
and we can do all our incore operations there. Our logging of changes&lt;br /&gt;
is based on the BMBT buffers, so getting rid of the iext layer would&lt;br /&gt;
not impact the transaction subsystem at all.&lt;br /&gt;
&lt;br /&gt;
Such integration with the generic code will also allow development&lt;br /&gt;
of generic writeback routines for delayed allocation, unwritten&lt;br /&gt;
extents, etc that are not specific to a given filesystem.&lt;br /&gt;
&lt;br /&gt;
== Demand Paging of Large Inode Extent Maps ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Currently the inode extent map is pinned  in memory until the inode is&lt;br /&gt;
reclaimed. Hence an inode with millions of extents will pin a large&lt;br /&gt;
amount of memory and this can cause serious issues in low memory&lt;br /&gt;
situations. Ideally we would like to be able to page the extent&lt;br /&gt;
map in and out once they get to a certain size to avoid this&lt;br /&gt;
problem. This feature requires more investigation before an overall&lt;br /&gt;
approach can be detailed here.&lt;br /&gt;
&lt;br /&gt;
It should be noted that if we move to an extent-based page cache mapping&lt;br /&gt;
tree, the associated extent state tree can be used to track sparse&lt;br /&gt;
regions. That is, regions of the extent map that are not in memory&lt;br /&gt;
can be easily represented and acceesses to an unread region can then&lt;br /&gt;
be used to trigger demand loading.&lt;br /&gt;
&lt;br /&gt;
== Food For Thought (Crazy Ideas) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If we are not using inode buffers for logging changes to inodes, we should&lt;br /&gt;
consider whether we need them at all. What benefit do the buffers bring us when&lt;br /&gt;
all we will use them for is read or write I/O?  Would it be better to go&lt;br /&gt;
straight to the buftarg page cache and do page based I/O via submit_bio()?&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=Improving_inode_Caching&amp;diff=2130</id>
		<title>Improving inode Caching</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=Improving_inode_Caching&amp;diff=2130"/>
		<updated>2010-12-23T03:48:26Z</updated>

		<summary type="html">&lt;p&gt;Dgc: /* Reclaim Optimizations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Future Directions for XFS&lt;br /&gt;
&lt;br /&gt;
== Improving Inode Caching and Operation in XFS ==&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Thousand foot view:&lt;br /&gt;
&lt;br /&gt;
We want to drive inode lookup in a manner that is as parallel, scalable and low&lt;br /&gt;
overhead as possible. This means efficient indexing, lowering memory&lt;br /&gt;
consumption, simplifying the caching heirachy, removing duplication and&lt;br /&gt;
reducing/removing lock traffic.&lt;br /&gt;
&lt;br /&gt;
In addition, we want to provide a good foundation for simplifying inode I/O,&lt;br /&gt;
improving writeback clustering, preventing RMW of inode buffers under memory&lt;br /&gt;
pressure, reducing creation and deletion overhead and removing writeback of&lt;br /&gt;
unlogged changes completely.&lt;br /&gt;
&lt;br /&gt;
There are a variety of features in disconnected trees and patch sets that need&lt;br /&gt;
to be combined to acheive this - the basic structure needed to implement this is&lt;br /&gt;
already in mainline and that is the radix tree inode indexing.  Further&lt;br /&gt;
improvements are going to be based around this structure and using it&lt;br /&gt;
effectively to avoid needing other indexing mechanisms.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Discussion:&lt;br /&gt;
&lt;br /&gt;
== Combining XFS and VFS inodes ==&lt;br /&gt;
----------------------------&lt;br /&gt;
&lt;br /&gt;
Status: Done (October 2008)&lt;br /&gt;
&lt;br /&gt;
== Compressed Inode Cache ==&lt;br /&gt;
-----------------------------&lt;br /&gt;
&lt;br /&gt;
The XFs inode cache uses a lot of memory. We can avoid this problem by making&lt;br /&gt;
use of the compressed inode cache - only the active inodes are held in a&lt;br /&gt;
non-compressed form, hence most inodes will end up being cached in compressed&lt;br /&gt;
form rather than in the XFS/linux inode form.  The compressed form can reduce&lt;br /&gt;
the cached inode footprint to 200-300 bytes per inode instead of 1-1.1k that&lt;br /&gt;
they currently take on a 64bit system. Hence by moving to a compressed cache we&lt;br /&gt;
can greatly increase the number of inodes cached in a given amount of memory&lt;br /&gt;
which more that offsets any comparitive increase we will see from inodes in&lt;br /&gt;
reclaim. the compressed cache should really have a LRU and a shrinker as well&lt;br /&gt;
so that memory pressure will slowly trim it as memory demands occur. [Note:&lt;br /&gt;
this compressed cache is discussed further later on in the reclaim context.]&lt;br /&gt;
&lt;br /&gt;
== Fixed Inode Cache Size ==&lt;br /&gt;
&lt;br /&gt;
It is worth noting that for embedded systems and appliances it may be worth while allowing&lt;br /&gt;
the size of the caches to be fixed. Also, to prevent memory fragmentation&lt;br /&gt;
problems, we could simply allocate that memory to the compressed cache slab.&lt;br /&gt;
In effect, this would become a &#039;static slab&#039; in that it has a bound maximum&lt;br /&gt;
size and never frees and memory. When the cache is full, we reclaim an&lt;br /&gt;
object out of it for reuse - this could be done by triggering the shrinker&lt;br /&gt;
to reclaim from the LRU. This would prevent the compressed inode cache from&lt;br /&gt;
consuming excessive amounts of memory in tightly constrained evironments.&lt;br /&gt;
Such an extension to the slab caches does not look difficult to implement,&lt;br /&gt;
and would allow such customisation with minimal deviation from mainline code.&lt;br /&gt;
&lt;br /&gt;
== Bypassing the Linux Inode Cache ==&lt;br /&gt;
&lt;br /&gt;
Lookups: Done (October 2008)&lt;br /&gt;
&lt;br /&gt;
Tracking dirty inodes: Done&lt;br /&gt;
&lt;br /&gt;
Writeback of dirty inodes: Done&lt;br /&gt;
&lt;br /&gt;
Writeback of dirty pages: still executed the by VFS&lt;br /&gt;
&lt;br /&gt;
Now that we can track dirty inodes ourselves, we can pretty much isolate&lt;br /&gt;
writeback of both data and inodes from the generic pdflush code. If we add a&lt;br /&gt;
hook high up in the pdflush path that simply passes us a writeback control&lt;br /&gt;
structure with the current writeback guidelines, we can do writeback within&lt;br /&gt;
those guidelines in the most optimal fashion for XFS.&lt;br /&gt;
&lt;br /&gt;
== Avoiding the Generic pdflush Code ==&lt;br /&gt;
&lt;br /&gt;
Writeback of inodes via AIL: Done&lt;br /&gt;
&lt;br /&gt;
For pdflush driven writeback, we only want to write back data; all other inode&lt;br /&gt;
writeback should be driven from the AIL (our time ordered dirty metadata list)&lt;br /&gt;
or xfssyncd in a manner that is most optimal for XFS.&lt;br /&gt;
&lt;br /&gt;
Furthermore, if we implement our own pdflush method, we can parallelise it in&lt;br /&gt;
several ways. We can ensure that each filesystem has it&#039;s own flush thread or&lt;br /&gt;
thread pool, we can have a thread pool shared by all filesystems (like pdflush&lt;br /&gt;
currently operates), we can have a flush thread per inode radix tree, and so&lt;br /&gt;
one. The method of paralleisation is open for interpretation, but enabling&lt;br /&gt;
multiple flush threads to operate on a single filesystem is one of the necessary&lt;br /&gt;
requirements to avoid data writeback (and hence delayed allocation) being&lt;br /&gt;
limited to the throughput of a single CPU per filesystem.&lt;br /&gt;
&lt;br /&gt;
== Improving Inode Writeback == &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To optimise inode writeback, we really need to reduce the impact of inode&lt;br /&gt;
buffer read-modify-write cycles. XFS is capable of caching far more inodes in&lt;br /&gt;
memory than it has buffer space available for, so RMW cycles during inode&lt;br /&gt;
writeback under memory pressure are quite common. Firstly, we want to avoid&lt;br /&gt;
blocking pdflush at all costs.  Secondly, we want to issue as much localised&lt;br /&gt;
readahead as possible in ascending offset order to allow both elevator merging&lt;br /&gt;
of readahead and as little seeking as possible. Finally, we want to issue all&lt;br /&gt;
the write cycles as close together as possible to allow the same elevator and&lt;br /&gt;
I/O optimisations to take place.&lt;br /&gt;
&lt;br /&gt;
To do this, firstly we need the non-blocking inode flush semantics to issue&lt;br /&gt;
readahead on buffers that are not up-to-date rather than reading them&lt;br /&gt;
synchronously. Inode writeback already has the interface to handle inodes that&lt;br /&gt;
weren&#039;t flushed - we return EAGAIN from xfs_iflush() and the higher inode&lt;br /&gt;
writeback layers handle this appropriately. It would be easy to add another&lt;br /&gt;
flag to pass down to the buffer layer to say &#039;issue but don&#039;t wait for any&lt;br /&gt;
read&#039;. If we use a radix tree traversal to issue readahead in such a manner,&lt;br /&gt;
we&#039;ll get ascending offset readahead being issued.&lt;br /&gt;
&lt;br /&gt;
One problem with this is that we can issue too much readahead and thrash the&lt;br /&gt;
cache. A possible solution to this is to make the readahead a &#039;delayed read&#039;&lt;br /&gt;
and on I/o completion add it to a queue that holds a reference on the buffer.&lt;br /&gt;
If a followup read occurs soon after, we remove it from the queue and drop that&lt;br /&gt;
reference. This prevents the buffer from being reclaimed in betwen the&lt;br /&gt;
readahead completing and the real read being issued. We should also issue this&lt;br /&gt;
delayed read on buffers that are in the cache so that they don&#039;t get reclaimed&lt;br /&gt;
to make room for the readahead.&lt;br /&gt;
&lt;br /&gt;
To prevent buildup of delayed read buffers, we can periodically purge them -&lt;br /&gt;
those that are older than a given age (say 5 seconds) can be removed from the&lt;br /&gt;
list and their reference dropped. This will free the buffer and allow it&#039;s&lt;br /&gt;
pages to be reclaimed.&lt;br /&gt;
&lt;br /&gt;
Once we have done the readahead pass, we can then do a modify and writeback&lt;br /&gt;
pass over all the inodes, knowing that there will be no read cycles to delay&lt;br /&gt;
this step. Once again, a radix tree traversal gives us ascending order&lt;br /&gt;
writeback and hence the modified buffers we send to the device will be in&lt;br /&gt;
optimal order for merging and minimal seek overhead.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Contiguous Inode Allocation ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To make optimal use of the radix tree cache and enable wide-scale clustering of&lt;br /&gt;
inode writeback across multiple clusters, we really need to ensure that inode&lt;br /&gt;
allocation occurs in large contiguous chunks on disk. Right now we only&lt;br /&gt;
allocate chunks of 64 inodes at a time; ideally we want to allocate a stripe&lt;br /&gt;
unit (or multiple of) full of inodes at a time. This would allow inode&lt;br /&gt;
writeback clustering to do full stripe writes to the underlying RAID if there&lt;br /&gt;
are dirty inodes spanning the entire stripe unit.&lt;br /&gt;
&lt;br /&gt;
The problem with doing this is that we don&#039;t want to introduce the latency of&lt;br /&gt;
creating megabytes of inodes when only one is needed for the current operation.&lt;br /&gt;
Hence we need to push the inode creation into a background thread and use that&lt;br /&gt;
to create contiguous inode chunks asynchronously. This moves the actual on-disk&lt;br /&gt;
allocation of inodes out of the normal create path; it should always be able to&lt;br /&gt;
find a free inode without doing on disk allocation. This will simplify the&lt;br /&gt;
create path by removing the allocate-on-disk-then-retry-the-create double&lt;br /&gt;
transaction that currently occurs.&lt;br /&gt;
&lt;br /&gt;
As an aside, we could preallocate a small amount of inodes in each AG (10-20MB&lt;br /&gt;
of inodes per AG?) without impacting mkfs time too greatly. This would allow&lt;br /&gt;
the filesystem to be used immediately on the first mount without triggering&lt;br /&gt;
lots of background allocation. This could alsobe done after the first mount&lt;br /&gt;
occurs, but that could interfere with typical benchmarking situations. Another&lt;br /&gt;
good reason for this preallocation is that it will help reduce xfs_repair&lt;br /&gt;
runtime for most common filesystem usages.&lt;br /&gt;
&lt;br /&gt;
One of the issues that the background create will cause is a substantial amount&lt;br /&gt;
of log traffic - every inode buffer initialised will be logged in whole. Hence&lt;br /&gt;
if we create a megabyte of inodes, we&#039;ll be causing a megabyte of log traffic&lt;br /&gt;
just for the inode buffers we&#039;ve initialised.  This is relatively simple to fix&lt;br /&gt;
- we don&#039;t log the buffer, we just log the fact that we need to initialise&lt;br /&gt;
inodes in a given range.  In recovery, when we see this transaction, then we&lt;br /&gt;
build the buffers, initialise them and write them out. Hence, we don&#039;t need to&lt;br /&gt;
log the buffers used to initialise the inodes.&lt;br /&gt;
&lt;br /&gt;
Also, we can use the background allocations to keep track of recently allocated&lt;br /&gt;
inode regions in the per-ag. Using that information to select the next inode to&lt;br /&gt;
be used rather than requiring btree searches on every create will greatly reduce&lt;br /&gt;
the CPU overhead of workloads that create lots of new inodes. It is not clear&lt;br /&gt;
whether a single background thread will be able to allocate enough inodes&lt;br /&gt;
to keep up with demand from the rest of the system - we may need multiple&lt;br /&gt;
threads for large configurations.&lt;br /&gt;
&lt;br /&gt;
== Single Block Inode Allocation ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
One of the big problems we have withe filesystems that are approaching&lt;br /&gt;
full is that it can be hard to find a large enough extent to hold 64 inodes.&lt;br /&gt;
We&#039;ve had ENOSPC errors on inode allocation reported on filesystems that&lt;br /&gt;
are only 85% full. This is a sign of free space fragmentation, and it&lt;br /&gt;
prevents inode allocation from succeeding. We could (and should) write&lt;br /&gt;
a free space defragmenter, but that does not solve the problem - it&#039;s&lt;br /&gt;
reactive, not preventative.&lt;br /&gt;
&lt;br /&gt;
The main problem we have is that XFS uses inode chunk size and alignment&lt;br /&gt;
to optimise inode number to disk location conversion. That is, the conversion&lt;br /&gt;
becomes a single set of shifts and masks instead of an AGI btree lookup.&lt;br /&gt;
This optimisation substantially reduces the CPU and I/O overhead of&lt;br /&gt;
inode lookups, but it does limit our flexibility. If we break the&lt;br /&gt;
alignment restriction, every lookup has to go back to a btree search.&lt;br /&gt;
Hence we really want to avoid breaking chunk alignment and size&lt;br /&gt;
rules.&lt;br /&gt;
&lt;br /&gt;
An approach to avoiding violation of this rule is to be able to determine which&lt;br /&gt;
index to look up when parsing the inode number. For example, we could use the&lt;br /&gt;
high bit of the inode number to indicate that it is located in a non-aligned&lt;br /&gt;
inode chunk and hence needs to be looked up in the btree. This would avoid&lt;br /&gt;
the lookup penalty for correctly aligned inode chunks.&lt;br /&gt;
&lt;br /&gt;
If we then redefine the meaning of the contents of the AGI btree record for&lt;br /&gt;
such inode chunks, we do not need a new index to keep these in. Effectively,&lt;br /&gt;
we need to add a bitmask to the record to indicate which blocks inside&lt;br /&gt;
the chunk can actually contain inodes. We still use aligned/sized records,&lt;br /&gt;
but mask out the sections that we are not allowed to allocate inodes in.&lt;br /&gt;
Effectively, this would allow sparse inode chunks. There may be limitations&lt;br /&gt;
on the resolution of sparseness depending on inode size and block size,&lt;br /&gt;
but for the common cases of 4k block size and 256 or 512 byte inodes I&lt;br /&gt;
think we can run a fully sparse mapping for each inode chunk.&lt;br /&gt;
&lt;br /&gt;
This would allow us to allocate inode extents of any alignment and size&lt;br /&gt;
that fits *inside* the existing alignment/size limitations. That is,&lt;br /&gt;
a single extent allocation could not span two btree records, but can&lt;br /&gt;
lie anywhere inside a single record. It also means that we can do&lt;br /&gt;
multiple extent allocations within one btree record to make optimal&lt;br /&gt;
use of the fragmented free space.&lt;br /&gt;
&lt;br /&gt;
It should be noted that this will probably have impact on some of the&lt;br /&gt;
inode cluster buffer mapping and clustering algorithms. It is not clear&lt;br /&gt;
exactly what impact yet, but certainly write clustering will be affected.&lt;br /&gt;
Fortunately we&#039;ll be able to detect the inodes that will have this problem&lt;br /&gt;
by the high bit in the inode number.&lt;br /&gt;
&lt;br /&gt;
== Inode Unlink ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If we turn to look at unlink and reclaim interactions, there are a few&lt;br /&gt;
optimisations that can be made.  Firstly, we don&#039;t need to do inode inactivation&lt;br /&gt;
in reclaim threads - these transactions can easily be pushed to a background&lt;br /&gt;
thread. This means that xfs_inactive would be little more than a vmtruncate()&lt;br /&gt;
call and queuing to a workqueue. This will substantially speed up the processing&lt;br /&gt;
of prune_icache() - we&#039;ll get inodes moved into reclaim much faster than we do&lt;br /&gt;
right now.&lt;br /&gt;
&lt;br /&gt;
This will have a noticable effect, though. When inodes are unlinked the space&lt;br /&gt;
consumed by those inodes may not be immediately freed - it will be returned as&lt;br /&gt;
the inodes are processed through the reclaim threads. This means that userspace&lt;br /&gt;
monitoring tools such as &#039;df&#039; may not immediately reflect the result of a&lt;br /&gt;
completed unlink operation. This will be a user visible change in behaviour,&lt;br /&gt;
though in most cases should not affect anyone and for those that it does affect&lt;br /&gt;
a &#039;sync&#039; should be sufficient to wait for the space to be returned.&lt;br /&gt;
&lt;br /&gt;
Now that inodes to be unlinked are out of general circulation, we can make the&lt;br /&gt;
unlinked path more complex. It is desirable to move the unlinked list from the&lt;br /&gt;
inode buffer to the inode core, but that has locking implications for incore&lt;br /&gt;
unlinked. Hence we really need background thread processing to enable this to&lt;br /&gt;
work (i.e. being able to requeue inodes for later processing). To ensure that&lt;br /&gt;
to overhead of this work is not a limiting factor, we will probably need&lt;br /&gt;
multiple workqueue processing threads for this.&lt;br /&gt;
&lt;br /&gt;
Moving the logging to the inode core enables two things - it allows us to keep&lt;br /&gt;
an in-memory copy of the unlinked list off the perag and that allows us to remove&lt;br /&gt;
xfs_inotobp(). The in-memory unlinked list means we don&#039;t have to read and&lt;br /&gt;
traverse the buffers every time we need to find the previous buffer to remove an&lt;br /&gt;
inode from the list, but it does mean we have to take the inode lock. If the&lt;br /&gt;
previous inode is locked, then we can&#039;t remove the inode from the unlinked list&lt;br /&gt;
so we must requeue it for this to occur at a later time.&lt;br /&gt;
&lt;br /&gt;
Combined with the changes to inode create, we effectively will only use the&lt;br /&gt;
inode buffer in the transaction subsystem for marking the region stale when&lt;br /&gt;
freeing an inode chunk from disk (i.e. the default noikeep configuration). If&lt;br /&gt;
we are using large inode allocation, we don&#039;t want to be freeing random inode&lt;br /&gt;
chunks - this will just leave us with fragmented inode regions and undo all the&lt;br /&gt;
good work that was done originally.&lt;br /&gt;
&lt;br /&gt;
To avoid this, we should not be freeing inode chunks as soon as they no longer&lt;br /&gt;
have any empty inodes in them. We should periodically scan the AGI btree&lt;br /&gt;
looking for contiguous chunks that have no inodes allocated in them, and then&lt;br /&gt;
freeing the large contiguous regions we find in one go. It is likely this can&lt;br /&gt;
be done in a single transaction; it&#039;s one extent to be freed, along with a&lt;br /&gt;
contiguous set of records to be removed from the AGI btree so should not&lt;br /&gt;
require logging much at all. Also, the background scanning could be triggered&lt;br /&gt;
by a number of different events - low space in an AG, a large number of free&lt;br /&gt;
inodes in an AG, etc - as it doesn&#039;t need to be done frequently. As a result&lt;br /&gt;
of the lack of frequency that this needs to be done, it can probably be&lt;br /&gt;
handled by a single thread or delayed workqueue.&lt;br /&gt;
&lt;br /&gt;
Further optimisations are possible here - if we rule that the AGI btree is the&lt;br /&gt;
sole place that inodes are marked free or in-use (with the exception of&lt;br /&gt;
unlinked inodes attached to the AGI lists), then we can avoid the need to&lt;br /&gt;
write back unlinked inodes or read newly created inodes from disk.  This would&lt;br /&gt;
require all inodes to effectively use a random generation number assigned at&lt;br /&gt;
create time as we would not be reading it from disk - writing/reading the current&lt;br /&gt;
generation number appears to be the only real reason for doing this I/O. This&lt;br /&gt;
would require extra checks to determine if an inode is unlinked - we&lt;br /&gt;
need to do an imap lookup rather than reading it and then checking it is&lt;br /&gt;
valid if it is not already in memory. Avoiding the I/O, however, will greatly speed&lt;br /&gt;
up create and remove workloads. Note: the impact of this on the bulkstat algorithm&lt;br /&gt;
has not been determined yet.&lt;br /&gt;
&lt;br /&gt;
One of the issues we need to consider with this background inactivation is that&lt;br /&gt;
we will be able to defer a large quantity of inactivation transactions so we are&lt;br /&gt;
going to need to be careful about how much we allow to be queued. Simple queue&lt;br /&gt;
depth throttling should be all that is needed to keep this under control.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Reclaim Optimizations ==&lt;br /&gt;
&lt;br /&gt;
Tracking inodes for reclaim in radix tree: Done&lt;br /&gt;
Using RCU for radix tree reclaim walks: Done&lt;br /&gt;
Non-blocking background reclaim: Done&lt;br /&gt;
Parallelised shrinker based reclaim: Done&lt;br /&gt;
&lt;br /&gt;
Now that we have efficient unlink, we&#039;ve got to handle the reclaim of all the&lt;br /&gt;
inodes that are now dead or simply not referenced. For inodes that are dirty,&lt;br /&gt;
we need to write them out to clean them. For inodes that are clean and not&lt;br /&gt;
unlinked, we need to compress them down for more compact storage. This involves&lt;br /&gt;
some CPU overhead, but it is worth noting that reclaiming of clean inodes&lt;br /&gt;
typically only occurs when we are under memory pressure.&lt;br /&gt;
&lt;br /&gt;
By compressing the XFS inode in this case, we are effectively reducing the&lt;br /&gt;
memory usage of the inode rather than freeing it directly. If we then get&lt;br /&gt;
another operation on that inode (e.g. the working set is slightly larger than&lt;br /&gt;
can be held in linux+XFS inode pairs, we avoid having to read the inode off&lt;br /&gt;
disk again - it simply gets uncompressed out of the cache. In essence we use&lt;br /&gt;
the compressed inode cache as an exclusive second level cache - it has higher&lt;br /&gt;
density than the primary cache and higher load latency and CPU overhead,&lt;br /&gt;
but it still avoids I/O in exactly the same manner as the primary cache.&lt;br /&gt;
&lt;br /&gt;
We cannot allow unrestricted build-up of reclaimable inodes - the memory they&lt;br /&gt;
consume will be large, so we should be aiming to compress reclaimable inodes as&lt;br /&gt;
soon as they are clean.  This will prevent buildup of memory consuming&lt;br /&gt;
uncompressed inodes that are not likely to be referenced again immediately.&lt;br /&gt;
&lt;br /&gt;
This clean inode reclaimation process can be accelerated by triggering reclaim&lt;br /&gt;
on inode I/O completion. If the inode is clean and reclaimable we should&lt;br /&gt;
trigger immediate reclaim processing of that inode.  This will mean that&lt;br /&gt;
reclaim of newly cleaned inodes will not get held up behind reclaim of dirty&lt;br /&gt;
inodes.&lt;br /&gt;
&lt;br /&gt;
For inodes that are unlinked, we can simply free them in reclaim as theƦ&lt;br /&gt;
are no longer in use. We don&#039;t want to poison the compressed cache with&lt;br /&gt;
unlinked inodes, nor do we need to because we can allocate new inodes&lt;br /&gt;
without incurring I/O.&lt;br /&gt;
&lt;br /&gt;
Still, we may end up with lots of inodes queued for reclaim. We may need&lt;br /&gt;
to implement a throttle mechanism to slow down the rate at which inodes&lt;br /&gt;
are queued for reclaimation in the situation where the reclaim process&lt;br /&gt;
is not able to keep up. It should be noted that if we parallelise inode&lt;br /&gt;
writeback we should also be able to parallelise inode reclaim via&lt;br /&gt;
the same mechanism, so the need for throttling may relatively low&lt;br /&gt;
if we can have multiple inodes under reclaim at once.&lt;br /&gt;
&lt;br /&gt;
It should be noted that complexity is exposed by interactions with concurrent&lt;br /&gt;
lookups, especially if we move to RCU locking on the radix tree. Firstly, we&lt;br /&gt;
need to be able to do an atomic swap of the compressed inode for the&lt;br /&gt;
uncompressed inode in the radix tree (and vice versa), to be able to tell them&lt;br /&gt;
apart (magic #), and to have atomic reference counts to ensure we can avoid use&lt;br /&gt;
after free situations when lookups race with compression or freeing.&lt;br /&gt;
&lt;br /&gt;
Secondly, with the complex unlink/reclaim interactions we will need to be&lt;br /&gt;
careful to detect inodes in the process of reclaim - the lookupp process&lt;br /&gt;
will need to do different things depending on the state of reclaim. Indeed,&lt;br /&gt;
we will need to be able to cancel reclaim of an unlinked inode if we try&lt;br /&gt;
to allocate it before it has been fully unlinked or reclaimed. The same&lt;br /&gt;
can be said for an inode in the process of being compressed - if we get&lt;br /&gt;
a lookup during the compression process, we want to return the existing&lt;br /&gt;
inode, not have to wait, re-allocate and uncompress it again. These&lt;br /&gt;
are all solvable issues - they just add complexity.&lt;br /&gt;
&lt;br /&gt;
== Accelerated Reclaim of buftarg Page Cache for Inodes ==&lt;br /&gt;
----------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
For single use inodes or even read-only inodes, we read them in, use them, then&lt;br /&gt;
reclaim them. With the compressed cache, they&#039;ll get compressed and live a lot&lt;br /&gt;
longer in memory. However, we also will have the inode cluster buffer pages&lt;br /&gt;
sitting in memory for some length of time after the inode was read in. This can&lt;br /&gt;
consume a large amount of memory that will never be used again, and does not&lt;br /&gt;
get reclaimed until they are purged from the LRU by the VM.  It would be&lt;br /&gt;
advantageous to accelerate the reclaim of these pages so that they do not build&lt;br /&gt;
up unneccessarily.&lt;br /&gt;
&lt;br /&gt;
One method we could use for this would be to introduce our own page LRUs into&lt;br /&gt;
the buftarg cache that we can reclaim from. This would allow us to sort pages&lt;br /&gt;
according to their contents into different LRUs and periodically reclaim pages&lt;br /&gt;
of specific types that were not referenced. This, however, would introduce a&lt;br /&gt;
fair amount of complexity into the buffer cache that doesn&#039;t currently exist.&lt;br /&gt;
Also, from a higher perspective, it makes the buffer cache a complex&lt;br /&gt;
part-buffer cache, part VM frankenstein.&lt;br /&gt;
&lt;br /&gt;
A better method would appear to be to leverage the delayed read queue&lt;br /&gt;
mechanism. This delayed read queue pins read buffers for a short period of&lt;br /&gt;
time, and then if they have not been referenced they get torn down.  If, as&lt;br /&gt;
part of this delayed read buffer teardown procedure we all free the backing&lt;br /&gt;
pages completely, we acheive the exact same result as having our own LRUs to&lt;br /&gt;
manage the page cache. This seems much simpler and a much more holistic&lt;br /&gt;
approach to solving the problem than implementing page LRUs.&lt;br /&gt;
&lt;br /&gt;
As an aside, we already have the mechanism in place to vary buffer aging based&lt;br /&gt;
on their type. The Irix buffer cache used this to great effect when under&lt;br /&gt;
memory pressure and the XFS code that configured it still exists in the Linux&lt;br /&gt;
code base. However, the Linux XFS buffer cache has never implemented any&lt;br /&gt;
mechanism to allow this functionality to be exploited. A delayed buffer reclaim&lt;br /&gt;
mechanism as described above could be greatly enhanced by making use of this&lt;br /&gt;
code in XFS.&lt;br /&gt;
&lt;br /&gt;
== Killing Bufferheads (a.k.a &amp;quot;Die, buggerheads, Die!&amp;quot;) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[This is not strictly about inode caching, but doesn&#039;t fit into&lt;br /&gt;
other areas of development as closely as it does to inode caching&lt;br /&gt;
optimisations.]&lt;br /&gt;
&lt;br /&gt;
XFS is extent based. The Linux page cache is block based. Hence for&lt;br /&gt;
every cached page in memory, we have to attach a structure for mapping&lt;br /&gt;
the blocks on that page back to to the on-disk location. In XFs, we also&lt;br /&gt;
use this to hold state for delayed allocation and unwritten extent blocks&lt;br /&gt;
so the generic code can do the right thing when necessary. We also&lt;br /&gt;
use it to avoid extent lookups at various times within the XFS I/O&lt;br /&gt;
path.&lt;br /&gt;
&lt;br /&gt;
However, this has a massive cost. While XFS might represent the&lt;br /&gt;
disk mapping of a 1GB extent in 24 bytes of memory, the page cache&lt;br /&gt;
requires 262,144 bufferheads (assuming 4k block size) to represent the&lt;br /&gt;
same mapping. That&#039;s roughly 14MB of memory neededtoo represent that.&lt;br /&gt;
&lt;br /&gt;
Chris Mason wrote an extent map representation for page cache state&lt;br /&gt;
and mappings for BTRFS; that code is mostly generic and could be&lt;br /&gt;
adapted to XFS. This would allow us to hold all the page cache state&lt;br /&gt;
in extent format and greatly reduce the memory overhead that it currently&lt;br /&gt;
has. The tradeoff is increased CPU overhead due to tree lookups where&lt;br /&gt;
structure lookups currently are used. Still, this has much lower&lt;br /&gt;
overhead than xfs_bmapi() based lookups, so the penalty is going to&lt;br /&gt;
be lower than if we did these lookups right now.&lt;br /&gt;
&lt;br /&gt;
If we make this change, we would then have three levels of extent&lt;br /&gt;
caching:&lt;br /&gt;
&lt;br /&gt;
	- the BMBT buffers&lt;br /&gt;
	- the XFS incore inode extent tree (iext*)&lt;br /&gt;
	- the page cache extent map tree&lt;br /&gt;
&lt;br /&gt;
Effectively, the XFS incore inode extent tree becomes redundant - all&lt;br /&gt;
the extent state it holds can be moved to the generic page cache tree&lt;br /&gt;
and we can do all our incore operations there. Our logging of changes&lt;br /&gt;
is based on the BMBT buffers, so getting rid of the iext layer would&lt;br /&gt;
not impact the transaction subsystem at all.&lt;br /&gt;
&lt;br /&gt;
Such integration with the generic code will also allow development&lt;br /&gt;
of generic writeback routines for delayed allocation, unwritten&lt;br /&gt;
extents, etc that are not specific to a given filesystem.&lt;br /&gt;
&lt;br /&gt;
== Demand Paging of Large Inode Extent Maps ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Currently the inode extent map is pinned  in memory until the inode is&lt;br /&gt;
reclaimed. Hence an inode with millions of extents will pin a large&lt;br /&gt;
amount of memory and this can cause serious issues in low memory&lt;br /&gt;
situations. Ideally we would like to be able to page the extent&lt;br /&gt;
map in and out once they get to a certain size to avoid this&lt;br /&gt;
problem. This feature requires more investigation before an overall&lt;br /&gt;
approach can be detailed here.&lt;br /&gt;
&lt;br /&gt;
It should be noted that if we move to an extent-based page cache mapping&lt;br /&gt;
tree, the associated extent state tree can be used to track sparse&lt;br /&gt;
regions. That is, regions of the extent map that are not in memory&lt;br /&gt;
can be easily represented and acceesses to an unread region can then&lt;br /&gt;
be used to trigger demand loading.&lt;br /&gt;
&lt;br /&gt;
== Food For Thought (Crazy Ideas) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If we are not using inode buffers for logging changes to inodes, we should&lt;br /&gt;
consider whether we need them at all. What benefit do the buffers bring us when&lt;br /&gt;
all we will use them for is read or write I/O?  Would it be better to go&lt;br /&gt;
straight to the buftarg page cache and do page based I/O via submit_bio()?&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=Improving_inode_Caching&amp;diff=2129</id>
		<title>Improving inode Caching</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=Improving_inode_Caching&amp;diff=2129"/>
		<updated>2010-12-23T03:42:48Z</updated>

		<summary type="html">&lt;p&gt;Dgc: /* Avoiding the Generic pdflush Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Future Directions for XFS&lt;br /&gt;
&lt;br /&gt;
== Improving Inode Caching and Operation in XFS ==&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Thousand foot view:&lt;br /&gt;
&lt;br /&gt;
We want to drive inode lookup in a manner that is as parallel, scalable and low&lt;br /&gt;
overhead as possible. This means efficient indexing, lowering memory&lt;br /&gt;
consumption, simplifying the caching heirachy, removing duplication and&lt;br /&gt;
reducing/removing lock traffic.&lt;br /&gt;
&lt;br /&gt;
In addition, we want to provide a good foundation for simplifying inode I/O,&lt;br /&gt;
improving writeback clustering, preventing RMW of inode buffers under memory&lt;br /&gt;
pressure, reducing creation and deletion overhead and removing writeback of&lt;br /&gt;
unlogged changes completely.&lt;br /&gt;
&lt;br /&gt;
There are a variety of features in disconnected trees and patch sets that need&lt;br /&gt;
to be combined to acheive this - the basic structure needed to implement this is&lt;br /&gt;
already in mainline and that is the radix tree inode indexing.  Further&lt;br /&gt;
improvements are going to be based around this structure and using it&lt;br /&gt;
effectively to avoid needing other indexing mechanisms.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Discussion:&lt;br /&gt;
&lt;br /&gt;
== Combining XFS and VFS inodes ==&lt;br /&gt;
----------------------------&lt;br /&gt;
&lt;br /&gt;
Status: Done (October 2008)&lt;br /&gt;
&lt;br /&gt;
== Compressed Inode Cache ==&lt;br /&gt;
-----------------------------&lt;br /&gt;
&lt;br /&gt;
The XFs inode cache uses a lot of memory. We can avoid this problem by making&lt;br /&gt;
use of the compressed inode cache - only the active inodes are held in a&lt;br /&gt;
non-compressed form, hence most inodes will end up being cached in compressed&lt;br /&gt;
form rather than in the XFS/linux inode form.  The compressed form can reduce&lt;br /&gt;
the cached inode footprint to 200-300 bytes per inode instead of 1-1.1k that&lt;br /&gt;
they currently take on a 64bit system. Hence by moving to a compressed cache we&lt;br /&gt;
can greatly increase the number of inodes cached in a given amount of memory&lt;br /&gt;
which more that offsets any comparitive increase we will see from inodes in&lt;br /&gt;
reclaim. the compressed cache should really have a LRU and a shrinker as well&lt;br /&gt;
so that memory pressure will slowly trim it as memory demands occur. [Note:&lt;br /&gt;
this compressed cache is discussed further later on in the reclaim context.]&lt;br /&gt;
&lt;br /&gt;
== Fixed Inode Cache Size ==&lt;br /&gt;
&lt;br /&gt;
It is worth noting that for embedded systems and appliances it may be worth while allowing&lt;br /&gt;
the size of the caches to be fixed. Also, to prevent memory fragmentation&lt;br /&gt;
problems, we could simply allocate that memory to the compressed cache slab.&lt;br /&gt;
In effect, this would become a &#039;static slab&#039; in that it has a bound maximum&lt;br /&gt;
size and never frees and memory. When the cache is full, we reclaim an&lt;br /&gt;
object out of it for reuse - this could be done by triggering the shrinker&lt;br /&gt;
to reclaim from the LRU. This would prevent the compressed inode cache from&lt;br /&gt;
consuming excessive amounts of memory in tightly constrained evironments.&lt;br /&gt;
Such an extension to the slab caches does not look difficult to implement,&lt;br /&gt;
and would allow such customisation with minimal deviation from mainline code.&lt;br /&gt;
&lt;br /&gt;
== Bypassing the Linux Inode Cache ==&lt;br /&gt;
&lt;br /&gt;
Lookups: Done (October 2008)&lt;br /&gt;
&lt;br /&gt;
Tracking dirty inodes: Done&lt;br /&gt;
&lt;br /&gt;
Writeback of dirty inodes: Done&lt;br /&gt;
&lt;br /&gt;
Writeback of dirty pages: still executed the by VFS&lt;br /&gt;
&lt;br /&gt;
Now that we can track dirty inodes ourselves, we can pretty much isolate&lt;br /&gt;
writeback of both data and inodes from the generic pdflush code. If we add a&lt;br /&gt;
hook high up in the pdflush path that simply passes us a writeback control&lt;br /&gt;
structure with the current writeback guidelines, we can do writeback within&lt;br /&gt;
those guidelines in the most optimal fashion for XFS.&lt;br /&gt;
&lt;br /&gt;
== Avoiding the Generic pdflush Code ==&lt;br /&gt;
&lt;br /&gt;
Writeback of inodes via AIL: Done&lt;br /&gt;
&lt;br /&gt;
For pdflush driven writeback, we only want to write back data; all other inode&lt;br /&gt;
writeback should be driven from the AIL (our time ordered dirty metadata list)&lt;br /&gt;
or xfssyncd in a manner that is most optimal for XFS.&lt;br /&gt;
&lt;br /&gt;
Furthermore, if we implement our own pdflush method, we can parallelise it in&lt;br /&gt;
several ways. We can ensure that each filesystem has it&#039;s own flush thread or&lt;br /&gt;
thread pool, we can have a thread pool shared by all filesystems (like pdflush&lt;br /&gt;
currently operates), we can have a flush thread per inode radix tree, and so&lt;br /&gt;
one. The method of paralleisation is open for interpretation, but enabling&lt;br /&gt;
multiple flush threads to operate on a single filesystem is one of the necessary&lt;br /&gt;
requirements to avoid data writeback (and hence delayed allocation) being&lt;br /&gt;
limited to the throughput of a single CPU per filesystem.&lt;br /&gt;
&lt;br /&gt;
== Improving Inode Writeback == &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To optimise inode writeback, we really need to reduce the impact of inode&lt;br /&gt;
buffer read-modify-write cycles. XFS is capable of caching far more inodes in&lt;br /&gt;
memory than it has buffer space available for, so RMW cycles during inode&lt;br /&gt;
writeback under memory pressure are quite common. Firstly, we want to avoid&lt;br /&gt;
blocking pdflush at all costs.  Secondly, we want to issue as much localised&lt;br /&gt;
readahead as possible in ascending offset order to allow both elevator merging&lt;br /&gt;
of readahead and as little seeking as possible. Finally, we want to issue all&lt;br /&gt;
the write cycles as close together as possible to allow the same elevator and&lt;br /&gt;
I/O optimisations to take place.&lt;br /&gt;
&lt;br /&gt;
To do this, firstly we need the non-blocking inode flush semantics to issue&lt;br /&gt;
readahead on buffers that are not up-to-date rather than reading them&lt;br /&gt;
synchronously. Inode writeback already has the interface to handle inodes that&lt;br /&gt;
weren&#039;t flushed - we return EAGAIN from xfs_iflush() and the higher inode&lt;br /&gt;
writeback layers handle this appropriately. It would be easy to add another&lt;br /&gt;
flag to pass down to the buffer layer to say &#039;issue but don&#039;t wait for any&lt;br /&gt;
read&#039;. If we use a radix tree traversal to issue readahead in such a manner,&lt;br /&gt;
we&#039;ll get ascending offset readahead being issued.&lt;br /&gt;
&lt;br /&gt;
One problem with this is that we can issue too much readahead and thrash the&lt;br /&gt;
cache. A possible solution to this is to make the readahead a &#039;delayed read&#039;&lt;br /&gt;
and on I/o completion add it to a queue that holds a reference on the buffer.&lt;br /&gt;
If a followup read occurs soon after, we remove it from the queue and drop that&lt;br /&gt;
reference. This prevents the buffer from being reclaimed in betwen the&lt;br /&gt;
readahead completing and the real read being issued. We should also issue this&lt;br /&gt;
delayed read on buffers that are in the cache so that they don&#039;t get reclaimed&lt;br /&gt;
to make room for the readahead.&lt;br /&gt;
&lt;br /&gt;
To prevent buildup of delayed read buffers, we can periodically purge them -&lt;br /&gt;
those that are older than a given age (say 5 seconds) can be removed from the&lt;br /&gt;
list and their reference dropped. This will free the buffer and allow it&#039;s&lt;br /&gt;
pages to be reclaimed.&lt;br /&gt;
&lt;br /&gt;
Once we have done the readahead pass, we can then do a modify and writeback&lt;br /&gt;
pass over all the inodes, knowing that there will be no read cycles to delay&lt;br /&gt;
this step. Once again, a radix tree traversal gives us ascending order&lt;br /&gt;
writeback and hence the modified buffers we send to the device will be in&lt;br /&gt;
optimal order for merging and minimal seek overhead.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Contiguous Inode Allocation ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To make optimal use of the radix tree cache and enable wide-scale clustering of&lt;br /&gt;
inode writeback across multiple clusters, we really need to ensure that inode&lt;br /&gt;
allocation occurs in large contiguous chunks on disk. Right now we only&lt;br /&gt;
allocate chunks of 64 inodes at a time; ideally we want to allocate a stripe&lt;br /&gt;
unit (or multiple of) full of inodes at a time. This would allow inode&lt;br /&gt;
writeback clustering to do full stripe writes to the underlying RAID if there&lt;br /&gt;
are dirty inodes spanning the entire stripe unit.&lt;br /&gt;
&lt;br /&gt;
The problem with doing this is that we don&#039;t want to introduce the latency of&lt;br /&gt;
creating megabytes of inodes when only one is needed for the current operation.&lt;br /&gt;
Hence we need to push the inode creation into a background thread and use that&lt;br /&gt;
to create contiguous inode chunks asynchronously. This moves the actual on-disk&lt;br /&gt;
allocation of inodes out of the normal create path; it should always be able to&lt;br /&gt;
find a free inode without doing on disk allocation. This will simplify the&lt;br /&gt;
create path by removing the allocate-on-disk-then-retry-the-create double&lt;br /&gt;
transaction that currently occurs.&lt;br /&gt;
&lt;br /&gt;
As an aside, we could preallocate a small amount of inodes in each AG (10-20MB&lt;br /&gt;
of inodes per AG?) without impacting mkfs time too greatly. This would allow&lt;br /&gt;
the filesystem to be used immediately on the first mount without triggering&lt;br /&gt;
lots of background allocation. This could alsobe done after the first mount&lt;br /&gt;
occurs, but that could interfere with typical benchmarking situations. Another&lt;br /&gt;
good reason for this preallocation is that it will help reduce xfs_repair&lt;br /&gt;
runtime for most common filesystem usages.&lt;br /&gt;
&lt;br /&gt;
One of the issues that the background create will cause is a substantial amount&lt;br /&gt;
of log traffic - every inode buffer initialised will be logged in whole. Hence&lt;br /&gt;
if we create a megabyte of inodes, we&#039;ll be causing a megabyte of log traffic&lt;br /&gt;
just for the inode buffers we&#039;ve initialised.  This is relatively simple to fix&lt;br /&gt;
- we don&#039;t log the buffer, we just log the fact that we need to initialise&lt;br /&gt;
inodes in a given range.  In recovery, when we see this transaction, then we&lt;br /&gt;
build the buffers, initialise them and write them out. Hence, we don&#039;t need to&lt;br /&gt;
log the buffers used to initialise the inodes.&lt;br /&gt;
&lt;br /&gt;
Also, we can use the background allocations to keep track of recently allocated&lt;br /&gt;
inode regions in the per-ag. Using that information to select the next inode to&lt;br /&gt;
be used rather than requiring btree searches on every create will greatly reduce&lt;br /&gt;
the CPU overhead of workloads that create lots of new inodes. It is not clear&lt;br /&gt;
whether a single background thread will be able to allocate enough inodes&lt;br /&gt;
to keep up with demand from the rest of the system - we may need multiple&lt;br /&gt;
threads for large configurations.&lt;br /&gt;
&lt;br /&gt;
== Single Block Inode Allocation ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
One of the big problems we have withe filesystems that are approaching&lt;br /&gt;
full is that it can be hard to find a large enough extent to hold 64 inodes.&lt;br /&gt;
We&#039;ve had ENOSPC errors on inode allocation reported on filesystems that&lt;br /&gt;
are only 85% full. This is a sign of free space fragmentation, and it&lt;br /&gt;
prevents inode allocation from succeeding. We could (and should) write&lt;br /&gt;
a free space defragmenter, but that does not solve the problem - it&#039;s&lt;br /&gt;
reactive, not preventative.&lt;br /&gt;
&lt;br /&gt;
The main problem we have is that XFS uses inode chunk size and alignment&lt;br /&gt;
to optimise inode number to disk location conversion. That is, the conversion&lt;br /&gt;
becomes a single set of shifts and masks instead of an AGI btree lookup.&lt;br /&gt;
This optimisation substantially reduces the CPU and I/O overhead of&lt;br /&gt;
inode lookups, but it does limit our flexibility. If we break the&lt;br /&gt;
alignment restriction, every lookup has to go back to a btree search.&lt;br /&gt;
Hence we really want to avoid breaking chunk alignment and size&lt;br /&gt;
rules.&lt;br /&gt;
&lt;br /&gt;
An approach to avoiding violation of this rule is to be able to determine which&lt;br /&gt;
index to look up when parsing the inode number. For example, we could use the&lt;br /&gt;
high bit of the inode number to indicate that it is located in a non-aligned&lt;br /&gt;
inode chunk and hence needs to be looked up in the btree. This would avoid&lt;br /&gt;
the lookup penalty for correctly aligned inode chunks.&lt;br /&gt;
&lt;br /&gt;
If we then redefine the meaning of the contents of the AGI btree record for&lt;br /&gt;
such inode chunks, we do not need a new index to keep these in. Effectively,&lt;br /&gt;
we need to add a bitmask to the record to indicate which blocks inside&lt;br /&gt;
the chunk can actually contain inodes. We still use aligned/sized records,&lt;br /&gt;
but mask out the sections that we are not allowed to allocate inodes in.&lt;br /&gt;
Effectively, this would allow sparse inode chunks. There may be limitations&lt;br /&gt;
on the resolution of sparseness depending on inode size and block size,&lt;br /&gt;
but for the common cases of 4k block size and 256 or 512 byte inodes I&lt;br /&gt;
think we can run a fully sparse mapping for each inode chunk.&lt;br /&gt;
&lt;br /&gt;
This would allow us to allocate inode extents of any alignment and size&lt;br /&gt;
that fits *inside* the existing alignment/size limitations. That is,&lt;br /&gt;
a single extent allocation could not span two btree records, but can&lt;br /&gt;
lie anywhere inside a single record. It also means that we can do&lt;br /&gt;
multiple extent allocations within one btree record to make optimal&lt;br /&gt;
use of the fragmented free space.&lt;br /&gt;
&lt;br /&gt;
It should be noted that this will probably have impact on some of the&lt;br /&gt;
inode cluster buffer mapping and clustering algorithms. It is not clear&lt;br /&gt;
exactly what impact yet, but certainly write clustering will be affected.&lt;br /&gt;
Fortunately we&#039;ll be able to detect the inodes that will have this problem&lt;br /&gt;
by the high bit in the inode number.&lt;br /&gt;
&lt;br /&gt;
== Inode Unlink ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If we turn to look at unlink and reclaim interactions, there are a few&lt;br /&gt;
optimisations that can be made.  Firstly, we don&#039;t need to do inode inactivation&lt;br /&gt;
in reclaim threads - these transactions can easily be pushed to a background&lt;br /&gt;
thread. This means that xfs_inactive would be little more than a vmtruncate()&lt;br /&gt;
call and queuing to a workqueue. This will substantially speed up the processing&lt;br /&gt;
of prune_icache() - we&#039;ll get inodes moved into reclaim much faster than we do&lt;br /&gt;
right now.&lt;br /&gt;
&lt;br /&gt;
This will have a noticable effect, though. When inodes are unlinked the space&lt;br /&gt;
consumed by those inodes may not be immediately freed - it will be returned as&lt;br /&gt;
the inodes are processed through the reclaim threads. This means that userspace&lt;br /&gt;
monitoring tools such as &#039;df&#039; may not immediately reflect the result of a&lt;br /&gt;
completed unlink operation. This will be a user visible change in behaviour,&lt;br /&gt;
though in most cases should not affect anyone and for those that it does affect&lt;br /&gt;
a &#039;sync&#039; should be sufficient to wait for the space to be returned.&lt;br /&gt;
&lt;br /&gt;
Now that inodes to be unlinked are out of general circulation, we can make the&lt;br /&gt;
unlinked path more complex. It is desirable to move the unlinked list from the&lt;br /&gt;
inode buffer to the inode core, but that has locking implications for incore&lt;br /&gt;
unlinked. Hence we really need background thread processing to enable this to&lt;br /&gt;
work (i.e. being able to requeue inodes for later processing). To ensure that&lt;br /&gt;
to overhead of this work is not a limiting factor, we will probably need&lt;br /&gt;
multiple workqueue processing threads for this.&lt;br /&gt;
&lt;br /&gt;
Moving the logging to the inode core enables two things - it allows us to keep&lt;br /&gt;
an in-memory copy of the unlinked list off the perag and that allows us to remove&lt;br /&gt;
xfs_inotobp(). The in-memory unlinked list means we don&#039;t have to read and&lt;br /&gt;
traverse the buffers every time we need to find the previous buffer to remove an&lt;br /&gt;
inode from the list, but it does mean we have to take the inode lock. If the&lt;br /&gt;
previous inode is locked, then we can&#039;t remove the inode from the unlinked list&lt;br /&gt;
so we must requeue it for this to occur at a later time.&lt;br /&gt;
&lt;br /&gt;
Combined with the changes to inode create, we effectively will only use the&lt;br /&gt;
inode buffer in the transaction subsystem for marking the region stale when&lt;br /&gt;
freeing an inode chunk from disk (i.e. the default noikeep configuration). If&lt;br /&gt;
we are using large inode allocation, we don&#039;t want to be freeing random inode&lt;br /&gt;
chunks - this will just leave us with fragmented inode regions and undo all the&lt;br /&gt;
good work that was done originally.&lt;br /&gt;
&lt;br /&gt;
To avoid this, we should not be freeing inode chunks as soon as they no longer&lt;br /&gt;
have any empty inodes in them. We should periodically scan the AGI btree&lt;br /&gt;
looking for contiguous chunks that have no inodes allocated in them, and then&lt;br /&gt;
freeing the large contiguous regions we find in one go. It is likely this can&lt;br /&gt;
be done in a single transaction; it&#039;s one extent to be freed, along with a&lt;br /&gt;
contiguous set of records to be removed from the AGI btree so should not&lt;br /&gt;
require logging much at all. Also, the background scanning could be triggered&lt;br /&gt;
by a number of different events - low space in an AG, a large number of free&lt;br /&gt;
inodes in an AG, etc - as it doesn&#039;t need to be done frequently. As a result&lt;br /&gt;
of the lack of frequency that this needs to be done, it can probably be&lt;br /&gt;
handled by a single thread or delayed workqueue.&lt;br /&gt;
&lt;br /&gt;
Further optimisations are possible here - if we rule that the AGI btree is the&lt;br /&gt;
sole place that inodes are marked free or in-use (with the exception of&lt;br /&gt;
unlinked inodes attached to the AGI lists), then we can avoid the need to&lt;br /&gt;
write back unlinked inodes or read newly created inodes from disk.  This would&lt;br /&gt;
require all inodes to effectively use a random generation number assigned at&lt;br /&gt;
create time as we would not be reading it from disk - writing/reading the current&lt;br /&gt;
generation number appears to be the only real reason for doing this I/O. This&lt;br /&gt;
would require extra checks to determine if an inode is unlinked - we&lt;br /&gt;
need to do an imap lookup rather than reading it and then checking it is&lt;br /&gt;
valid if it is not already in memory. Avoiding the I/O, however, will greatly speed&lt;br /&gt;
up create and remove workloads. Note: the impact of this on the bulkstat algorithm&lt;br /&gt;
has not been determined yet.&lt;br /&gt;
&lt;br /&gt;
One of the issues we need to consider with this background inactivation is that&lt;br /&gt;
we will be able to defer a large quantity of inactivation transactions so we are&lt;br /&gt;
going to need to be careful about how much we allow to be queued. Simple queue&lt;br /&gt;
depth throttling should be all that is needed to keep this under control.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Reclaim Optimizations ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now that we have efficient unlink, we&#039;ve got to handle the reclaim of all the&lt;br /&gt;
inodes that are now dead or simply not referenced. For inodes that are dirty,&lt;br /&gt;
we need to write them out to clean them. For inodes that are clean and not&lt;br /&gt;
unlinked, we need to compress them down for more compact storage. This involves&lt;br /&gt;
some CPU overhead, but it is worth noting that reclaiming of clean inodes&lt;br /&gt;
typically only occurs when we are under memory pressure.&lt;br /&gt;
&lt;br /&gt;
By compressing the XFS inode in this case, we are effectively reducing the&lt;br /&gt;
memory usage of the inode rather than freeing it directly. If we then get&lt;br /&gt;
another operation on that inode (e.g. the working set is slightly larger than&lt;br /&gt;
can be held in linux+XFS inode pairs, we avoid having to read the inode off&lt;br /&gt;
disk again - it simply gets uncompressed out of the cache. In essence we use&lt;br /&gt;
the compressed inode cache as an exclusive second level cache - it has higher&lt;br /&gt;
density than the primary cache and higher load latency and CPU overhead,&lt;br /&gt;
but it still avoids I/O in exactly the same manner as the primary cache.&lt;br /&gt;
&lt;br /&gt;
We cannot allow unrestricted build-up of reclaimable inodes - the memory they&lt;br /&gt;
consume will be large, so we should be aiming to compress reclaimable inodes as&lt;br /&gt;
soon as they are clean.  This will prevent buildup of memory consuming&lt;br /&gt;
uncompressed inodes that are not likely to be referenced again immediately.&lt;br /&gt;
&lt;br /&gt;
This clean inode reclaimation process can be accelerated by triggering reclaim&lt;br /&gt;
on inode I/O completion. If the inode is clean and reclaimable we should&lt;br /&gt;
trigger immediate reclaim processing of that inode.  This will mean that&lt;br /&gt;
reclaim of newly cleaned inodes will not get held up behind reclaim of dirty&lt;br /&gt;
inodes.&lt;br /&gt;
&lt;br /&gt;
For inodes that are unlinked, we can simply free them in reclaim as theƦ&lt;br /&gt;
are no longer in use. We don&#039;t want to poison the compressed cache with&lt;br /&gt;
unlinked inodes, nor do we need to because we can allocate new inodes&lt;br /&gt;
without incurring I/O.&lt;br /&gt;
&lt;br /&gt;
Still, we may end up with lots of inodes queued for reclaim. We may need&lt;br /&gt;
to implement a throttle mechanism to slow down the rate at which inodes&lt;br /&gt;
are queued for reclaimation in the situation where the reclaim process&lt;br /&gt;
is not able to keep up. It should be noted that if we parallelise inode&lt;br /&gt;
writeback we should also be able to parallelise inode reclaim via&lt;br /&gt;
the same mechanism, so the need for throttling may relatively low&lt;br /&gt;
if we can have multiple inodes under reclaim at once.&lt;br /&gt;
&lt;br /&gt;
It should be noted that complexity is exposed by interactions with concurrent&lt;br /&gt;
lookups, especially if we move to RCU locking on the radix tree. Firstly, we&lt;br /&gt;
need to be able to do an atomic swap of the compressed inode for the&lt;br /&gt;
uncompressed inode in the radix tree (and vice versa), to be able to tell them&lt;br /&gt;
apart (magic #), and to have atomic reference counts to ensure we can avoid use&lt;br /&gt;
after free situations when lookups race with compression or freeing.&lt;br /&gt;
&lt;br /&gt;
Secondly, with the complex unlink/reclaim interactions we will need to be&lt;br /&gt;
careful to detect inodes in the process of reclaim - the lookupp process&lt;br /&gt;
will need to do different things depending on the state of reclaim. Indeed,&lt;br /&gt;
we will need to be able to cancel reclaim of an unlinked inode if we try&lt;br /&gt;
to allocate it before it has been fully unlinked or reclaimed. The same&lt;br /&gt;
can be said for an inode in the process of being compressed - if we get&lt;br /&gt;
a lookup during the compression process, we want to return the existing&lt;br /&gt;
inode, not have to wait, re-allocate and uncompress it again. These&lt;br /&gt;
are all solvable issues - they just add complexity.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Accelerated Reclaim of buftarg Page Cache for Inodes ==&lt;br /&gt;
----------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
For single use inodes or even read-only inodes, we read them in, use them, then&lt;br /&gt;
reclaim them. With the compressed cache, they&#039;ll get compressed and live a lot&lt;br /&gt;
longer in memory. However, we also will have the inode cluster buffer pages&lt;br /&gt;
sitting in memory for some length of time after the inode was read in. This can&lt;br /&gt;
consume a large amount of memory that will never be used again, and does not&lt;br /&gt;
get reclaimed until they are purged from the LRU by the VM.  It would be&lt;br /&gt;
advantageous to accelerate the reclaim of these pages so that they do not build&lt;br /&gt;
up unneccessarily.&lt;br /&gt;
&lt;br /&gt;
One method we could use for this would be to introduce our own page LRUs into&lt;br /&gt;
the buftarg cache that we can reclaim from. This would allow us to sort pages&lt;br /&gt;
according to their contents into different LRUs and periodically reclaim pages&lt;br /&gt;
of specific types that were not referenced. This, however, would introduce a&lt;br /&gt;
fair amount of complexity into the buffer cache that doesn&#039;t currently exist.&lt;br /&gt;
Also, from a higher perspective, it makes the buffer cache a complex&lt;br /&gt;
part-buffer cache, part VM frankenstein.&lt;br /&gt;
&lt;br /&gt;
A better method would appear to be to leverage the delayed read queue&lt;br /&gt;
mechanism. This delayed read queue pins read buffers for a short period of&lt;br /&gt;
time, and then if they have not been referenced they get torn down.  If, as&lt;br /&gt;
part of this delayed read buffer teardown procedure we all free the backing&lt;br /&gt;
pages completely, we acheive the exact same result as having our own LRUs to&lt;br /&gt;
manage the page cache. This seems much simpler and a much more holistic&lt;br /&gt;
approach to solving the problem than implementing page LRUs.&lt;br /&gt;
&lt;br /&gt;
As an aside, we already have the mechanism in place to vary buffer aging based&lt;br /&gt;
on their type. The Irix buffer cache used this to great effect when under&lt;br /&gt;
memory pressure and the XFS code that configured it still exists in the Linux&lt;br /&gt;
code base. However, the Linux XFS buffer cache has never implemented any&lt;br /&gt;
mechanism to allow this functionality to be exploited. A delayed buffer reclaim&lt;br /&gt;
mechanism as described above could be greatly enhanced by making use of this&lt;br /&gt;
code in XFS.&lt;br /&gt;
&lt;br /&gt;
== Killing Bufferheads (a.k.a &amp;quot;Die, buggerheads, Die!&amp;quot;) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[This is not strictly about inode caching, but doesn&#039;t fit into&lt;br /&gt;
other areas of development as closely as it does to inode caching&lt;br /&gt;
optimisations.]&lt;br /&gt;
&lt;br /&gt;
XFS is extent based. The Linux page cache is block based. Hence for&lt;br /&gt;
every cached page in memory, we have to attach a structure for mapping&lt;br /&gt;
the blocks on that page back to to the on-disk location. In XFs, we also&lt;br /&gt;
use this to hold state for delayed allocation and unwritten extent blocks&lt;br /&gt;
so the generic code can do the right thing when necessary. We also&lt;br /&gt;
use it to avoid extent lookups at various times within the XFS I/O&lt;br /&gt;
path.&lt;br /&gt;
&lt;br /&gt;
However, this has a massive cost. While XFS might represent the&lt;br /&gt;
disk mapping of a 1GB extent in 24 bytes of memory, the page cache&lt;br /&gt;
requires 262,144 bufferheads (assuming 4k block size) to represent the&lt;br /&gt;
same mapping. That&#039;s roughly 14MB of memory neededtoo represent that.&lt;br /&gt;
&lt;br /&gt;
Chris Mason wrote an extent map representation for page cache state&lt;br /&gt;
and mappings for BTRFS; that code is mostly generic and could be&lt;br /&gt;
adapted to XFS. This would allow us to hold all the page cache state&lt;br /&gt;
in extent format and greatly reduce the memory overhead that it currently&lt;br /&gt;
has. The tradeoff is increased CPU overhead due to tree lookups where&lt;br /&gt;
structure lookups currently are used. Still, this has much lower&lt;br /&gt;
overhead than xfs_bmapi() based lookups, so the penalty is going to&lt;br /&gt;
be lower than if we did these lookups right now.&lt;br /&gt;
&lt;br /&gt;
If we make this change, we would then have three levels of extent&lt;br /&gt;
caching:&lt;br /&gt;
&lt;br /&gt;
	- the BMBT buffers&lt;br /&gt;
	- the XFS incore inode extent tree (iext*)&lt;br /&gt;
	- the page cache extent map tree&lt;br /&gt;
&lt;br /&gt;
Effectively, the XFS incore inode extent tree becomes redundant - all&lt;br /&gt;
the extent state it holds can be moved to the generic page cache tree&lt;br /&gt;
and we can do all our incore operations there. Our logging of changes&lt;br /&gt;
is based on the BMBT buffers, so getting rid of the iext layer would&lt;br /&gt;
not impact the transaction subsystem at all.&lt;br /&gt;
&lt;br /&gt;
Such integration with the generic code will also allow development&lt;br /&gt;
of generic writeback routines for delayed allocation, unwritten&lt;br /&gt;
extents, etc that are not specific to a given filesystem.&lt;br /&gt;
&lt;br /&gt;
== Demand Paging of Large Inode Extent Maps ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Currently the inode extent map is pinned  in memory until the inode is&lt;br /&gt;
reclaimed. Hence an inode with millions of extents will pin a large&lt;br /&gt;
amount of memory and this can cause serious issues in low memory&lt;br /&gt;
situations. Ideally we would like to be able to page the extent&lt;br /&gt;
map in and out once they get to a certain size to avoid this&lt;br /&gt;
problem. This feature requires more investigation before an overall&lt;br /&gt;
approach can be detailed here.&lt;br /&gt;
&lt;br /&gt;
It should be noted that if we move to an extent-based page cache mapping&lt;br /&gt;
tree, the associated extent state tree can be used to track sparse&lt;br /&gt;
regions. That is, regions of the extent map that are not in memory&lt;br /&gt;
can be easily represented and acceesses to an unread region can then&lt;br /&gt;
be used to trigger demand loading.&lt;br /&gt;
&lt;br /&gt;
== Food For Thought (Crazy Ideas) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If we are not using inode buffers for logging changes to inodes, we should&lt;br /&gt;
consider whether we need them at all. What benefit do the buffers bring us when&lt;br /&gt;
all we will use them for is read or write I/O?  Would it be better to go&lt;br /&gt;
straight to the buftarg page cache and do page based I/O via submit_bio()?&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=Improving_inode_Caching&amp;diff=2128</id>
		<title>Improving inode Caching</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=Improving_inode_Caching&amp;diff=2128"/>
		<updated>2010-12-23T03:41:39Z</updated>

		<summary type="html">&lt;p&gt;Dgc: /* Bypassing the Linux Inode Cache */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Future Directions for XFS&lt;br /&gt;
&lt;br /&gt;
== Improving Inode Caching and Operation in XFS ==&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Thousand foot view:&lt;br /&gt;
&lt;br /&gt;
We want to drive inode lookup in a manner that is as parallel, scalable and low&lt;br /&gt;
overhead as possible. This means efficient indexing, lowering memory&lt;br /&gt;
consumption, simplifying the caching heirachy, removing duplication and&lt;br /&gt;
reducing/removing lock traffic.&lt;br /&gt;
&lt;br /&gt;
In addition, we want to provide a good foundation for simplifying inode I/O,&lt;br /&gt;
improving writeback clustering, preventing RMW of inode buffers under memory&lt;br /&gt;
pressure, reducing creation and deletion overhead and removing writeback of&lt;br /&gt;
unlogged changes completely.&lt;br /&gt;
&lt;br /&gt;
There are a variety of features in disconnected trees and patch sets that need&lt;br /&gt;
to be combined to acheive this - the basic structure needed to implement this is&lt;br /&gt;
already in mainline and that is the radix tree inode indexing.  Further&lt;br /&gt;
improvements are going to be based around this structure and using it&lt;br /&gt;
effectively to avoid needing other indexing mechanisms.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Discussion:&lt;br /&gt;
&lt;br /&gt;
== Combining XFS and VFS inodes ==&lt;br /&gt;
----------------------------&lt;br /&gt;
&lt;br /&gt;
Status: Done (October 2008)&lt;br /&gt;
&lt;br /&gt;
== Compressed Inode Cache ==&lt;br /&gt;
-----------------------------&lt;br /&gt;
&lt;br /&gt;
The XFs inode cache uses a lot of memory. We can avoid this problem by making&lt;br /&gt;
use of the compressed inode cache - only the active inodes are held in a&lt;br /&gt;
non-compressed form, hence most inodes will end up being cached in compressed&lt;br /&gt;
form rather than in the XFS/linux inode form.  The compressed form can reduce&lt;br /&gt;
the cached inode footprint to 200-300 bytes per inode instead of 1-1.1k that&lt;br /&gt;
they currently take on a 64bit system. Hence by moving to a compressed cache we&lt;br /&gt;
can greatly increase the number of inodes cached in a given amount of memory&lt;br /&gt;
which more that offsets any comparitive increase we will see from inodes in&lt;br /&gt;
reclaim. the compressed cache should really have a LRU and a shrinker as well&lt;br /&gt;
so that memory pressure will slowly trim it as memory demands occur. [Note:&lt;br /&gt;
this compressed cache is discussed further later on in the reclaim context.]&lt;br /&gt;
&lt;br /&gt;
== Fixed Inode Cache Size ==&lt;br /&gt;
&lt;br /&gt;
It is worth noting that for embedded systems and appliances it may be worth while allowing&lt;br /&gt;
the size of the caches to be fixed. Also, to prevent memory fragmentation&lt;br /&gt;
problems, we could simply allocate that memory to the compressed cache slab.&lt;br /&gt;
In effect, this would become a &#039;static slab&#039; in that it has a bound maximum&lt;br /&gt;
size and never frees and memory. When the cache is full, we reclaim an&lt;br /&gt;
object out of it for reuse - this could be done by triggering the shrinker&lt;br /&gt;
to reclaim from the LRU. This would prevent the compressed inode cache from&lt;br /&gt;
consuming excessive amounts of memory in tightly constrained evironments.&lt;br /&gt;
Such an extension to the slab caches does not look difficult to implement,&lt;br /&gt;
and would allow such customisation with minimal deviation from mainline code.&lt;br /&gt;
&lt;br /&gt;
== Bypassing the Linux Inode Cache ==&lt;br /&gt;
&lt;br /&gt;
Lookups: Done (October 2008)&lt;br /&gt;
&lt;br /&gt;
Tracking dirty inodes: Done&lt;br /&gt;
&lt;br /&gt;
Writeback of dirty inodes: Done&lt;br /&gt;
&lt;br /&gt;
Writeback of dirty pages: still executed the by VFS&lt;br /&gt;
&lt;br /&gt;
Now that we can track dirty inodes ourselves, we can pretty much isolate&lt;br /&gt;
writeback of both data and inodes from the generic pdflush code. If we add a&lt;br /&gt;
hook high up in the pdflush path that simply passes us a writeback control&lt;br /&gt;
structure with the current writeback guidelines, we can do writeback within&lt;br /&gt;
those guidelines in the most optimal fashion for XFS.&lt;br /&gt;
&lt;br /&gt;
== Avoiding the Generic pdflush Code ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For pdflush driven writeback, we only want to write back data; all other inode&lt;br /&gt;
writeback should be driven from the AIL (our time ordered dirty metadata list)&lt;br /&gt;
or xfssyncd in a manner that is most optimal for XFS.&lt;br /&gt;
&lt;br /&gt;
Furthermore, if we implement our own pdflush method, we can parallelise it in&lt;br /&gt;
several ways. We can ensure that each filesystem has it&#039;s own flush thread or&lt;br /&gt;
thread pool, we can have a thread pool shared by all filesystems (like pdflush&lt;br /&gt;
currently operates), we can have a flush thread per inode radix tree, and so&lt;br /&gt;
one. The method of paralleisation is open for interpretation, but enabling&lt;br /&gt;
multiple flush threads to operate on a single filesystem is one of the necessary&lt;br /&gt;
requirements to avoid data writeback (and hence delayed allocation) being&lt;br /&gt;
limited to the throughput of a single CPU per filesystem.&lt;br /&gt;
&lt;br /&gt;
As it is, once data writeback is separated from inode writeback, we could&lt;br /&gt;
simply use pushing the AIL as a method of writing back metadata in the&lt;br /&gt;
background. There is no good reason for writing the inode immediately after&lt;br /&gt;
data if the inode is in the AIL - it will get written soon enough as the tail&lt;br /&gt;
of the AIL gets moved along. If we log all inode changes, then we&#039;ll be&lt;br /&gt;
unlikely to write the inode multiple times over it&#039;s dirty life-cycle as it&lt;br /&gt;
will continue to be moved forward in the AIL each time it is logged...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Improving Inode Writeback == &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To optimise inode writeback, we really need to reduce the impact of inode&lt;br /&gt;
buffer read-modify-write cycles. XFS is capable of caching far more inodes in&lt;br /&gt;
memory than it has buffer space available for, so RMW cycles during inode&lt;br /&gt;
writeback under memory pressure are quite common. Firstly, we want to avoid&lt;br /&gt;
blocking pdflush at all costs.  Secondly, we want to issue as much localised&lt;br /&gt;
readahead as possible in ascending offset order to allow both elevator merging&lt;br /&gt;
of readahead and as little seeking as possible. Finally, we want to issue all&lt;br /&gt;
the write cycles as close together as possible to allow the same elevator and&lt;br /&gt;
I/O optimisations to take place.&lt;br /&gt;
&lt;br /&gt;
To do this, firstly we need the non-blocking inode flush semantics to issue&lt;br /&gt;
readahead on buffers that are not up-to-date rather than reading them&lt;br /&gt;
synchronously. Inode writeback already has the interface to handle inodes that&lt;br /&gt;
weren&#039;t flushed - we return EAGAIN from xfs_iflush() and the higher inode&lt;br /&gt;
writeback layers handle this appropriately. It would be easy to add another&lt;br /&gt;
flag to pass down to the buffer layer to say &#039;issue but don&#039;t wait for any&lt;br /&gt;
read&#039;. If we use a radix tree traversal to issue readahead in such a manner,&lt;br /&gt;
we&#039;ll get ascending offset readahead being issued.&lt;br /&gt;
&lt;br /&gt;
One problem with this is that we can issue too much readahead and thrash the&lt;br /&gt;
cache. A possible solution to this is to make the readahead a &#039;delayed read&#039;&lt;br /&gt;
and on I/o completion add it to a queue that holds a reference on the buffer.&lt;br /&gt;
If a followup read occurs soon after, we remove it from the queue and drop that&lt;br /&gt;
reference. This prevents the buffer from being reclaimed in betwen the&lt;br /&gt;
readahead completing and the real read being issued. We should also issue this&lt;br /&gt;
delayed read on buffers that are in the cache so that they don&#039;t get reclaimed&lt;br /&gt;
to make room for the readahead.&lt;br /&gt;
&lt;br /&gt;
To prevent buildup of delayed read buffers, we can periodically purge them -&lt;br /&gt;
those that are older than a given age (say 5 seconds) can be removed from the&lt;br /&gt;
list and their reference dropped. This will free the buffer and allow it&#039;s&lt;br /&gt;
pages to be reclaimed.&lt;br /&gt;
&lt;br /&gt;
Once we have done the readahead pass, we can then do a modify and writeback&lt;br /&gt;
pass over all the inodes, knowing that there will be no read cycles to delay&lt;br /&gt;
this step. Once again, a radix tree traversal gives us ascending order&lt;br /&gt;
writeback and hence the modified buffers we send to the device will be in&lt;br /&gt;
optimal order for merging and minimal seek overhead.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Contiguous Inode Allocation ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To make optimal use of the radix tree cache and enable wide-scale clustering of&lt;br /&gt;
inode writeback across multiple clusters, we really need to ensure that inode&lt;br /&gt;
allocation occurs in large contiguous chunks on disk. Right now we only&lt;br /&gt;
allocate chunks of 64 inodes at a time; ideally we want to allocate a stripe&lt;br /&gt;
unit (or multiple of) full of inodes at a time. This would allow inode&lt;br /&gt;
writeback clustering to do full stripe writes to the underlying RAID if there&lt;br /&gt;
are dirty inodes spanning the entire stripe unit.&lt;br /&gt;
&lt;br /&gt;
The problem with doing this is that we don&#039;t want to introduce the latency of&lt;br /&gt;
creating megabytes of inodes when only one is needed for the current operation.&lt;br /&gt;
Hence we need to push the inode creation into a background thread and use that&lt;br /&gt;
to create contiguous inode chunks asynchronously. This moves the actual on-disk&lt;br /&gt;
allocation of inodes out of the normal create path; it should always be able to&lt;br /&gt;
find a free inode without doing on disk allocation. This will simplify the&lt;br /&gt;
create path by removing the allocate-on-disk-then-retry-the-create double&lt;br /&gt;
transaction that currently occurs.&lt;br /&gt;
&lt;br /&gt;
As an aside, we could preallocate a small amount of inodes in each AG (10-20MB&lt;br /&gt;
of inodes per AG?) without impacting mkfs time too greatly. This would allow&lt;br /&gt;
the filesystem to be used immediately on the first mount without triggering&lt;br /&gt;
lots of background allocation. This could alsobe done after the first mount&lt;br /&gt;
occurs, but that could interfere with typical benchmarking situations. Another&lt;br /&gt;
good reason for this preallocation is that it will help reduce xfs_repair&lt;br /&gt;
runtime for most common filesystem usages.&lt;br /&gt;
&lt;br /&gt;
One of the issues that the background create will cause is a substantial amount&lt;br /&gt;
of log traffic - every inode buffer initialised will be logged in whole. Hence&lt;br /&gt;
if we create a megabyte of inodes, we&#039;ll be causing a megabyte of log traffic&lt;br /&gt;
just for the inode buffers we&#039;ve initialised.  This is relatively simple to fix&lt;br /&gt;
- we don&#039;t log the buffer, we just log the fact that we need to initialise&lt;br /&gt;
inodes in a given range.  In recovery, when we see this transaction, then we&lt;br /&gt;
build the buffers, initialise them and write them out. Hence, we don&#039;t need to&lt;br /&gt;
log the buffers used to initialise the inodes.&lt;br /&gt;
&lt;br /&gt;
Also, we can use the background allocations to keep track of recently allocated&lt;br /&gt;
inode regions in the per-ag. Using that information to select the next inode to&lt;br /&gt;
be used rather than requiring btree searches on every create will greatly reduce&lt;br /&gt;
the CPU overhead of workloads that create lots of new inodes. It is not clear&lt;br /&gt;
whether a single background thread will be able to allocate enough inodes&lt;br /&gt;
to keep up with demand from the rest of the system - we may need multiple&lt;br /&gt;
threads for large configurations.&lt;br /&gt;
&lt;br /&gt;
== Single Block Inode Allocation ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
One of the big problems we have withe filesystems that are approaching&lt;br /&gt;
full is that it can be hard to find a large enough extent to hold 64 inodes.&lt;br /&gt;
We&#039;ve had ENOSPC errors on inode allocation reported on filesystems that&lt;br /&gt;
are only 85% full. This is a sign of free space fragmentation, and it&lt;br /&gt;
prevents inode allocation from succeeding. We could (and should) write&lt;br /&gt;
a free space defragmenter, but that does not solve the problem - it&#039;s&lt;br /&gt;
reactive, not preventative.&lt;br /&gt;
&lt;br /&gt;
The main problem we have is that XFS uses inode chunk size and alignment&lt;br /&gt;
to optimise inode number to disk location conversion. That is, the conversion&lt;br /&gt;
becomes a single set of shifts and masks instead of an AGI btree lookup.&lt;br /&gt;
This optimisation substantially reduces the CPU and I/O overhead of&lt;br /&gt;
inode lookups, but it does limit our flexibility. If we break the&lt;br /&gt;
alignment restriction, every lookup has to go back to a btree search.&lt;br /&gt;
Hence we really want to avoid breaking chunk alignment and size&lt;br /&gt;
rules.&lt;br /&gt;
&lt;br /&gt;
An approach to avoiding violation of this rule is to be able to determine which&lt;br /&gt;
index to look up when parsing the inode number. For example, we could use the&lt;br /&gt;
high bit of the inode number to indicate that it is located in a non-aligned&lt;br /&gt;
inode chunk and hence needs to be looked up in the btree. This would avoid&lt;br /&gt;
the lookup penalty for correctly aligned inode chunks.&lt;br /&gt;
&lt;br /&gt;
If we then redefine the meaning of the contents of the AGI btree record for&lt;br /&gt;
such inode chunks, we do not need a new index to keep these in. Effectively,&lt;br /&gt;
we need to add a bitmask to the record to indicate which blocks inside&lt;br /&gt;
the chunk can actually contain inodes. We still use aligned/sized records,&lt;br /&gt;
but mask out the sections that we are not allowed to allocate inodes in.&lt;br /&gt;
Effectively, this would allow sparse inode chunks. There may be limitations&lt;br /&gt;
on the resolution of sparseness depending on inode size and block size,&lt;br /&gt;
but for the common cases of 4k block size and 256 or 512 byte inodes I&lt;br /&gt;
think we can run a fully sparse mapping for each inode chunk.&lt;br /&gt;
&lt;br /&gt;
This would allow us to allocate inode extents of any alignment and size&lt;br /&gt;
that fits *inside* the existing alignment/size limitations. That is,&lt;br /&gt;
a single extent allocation could not span two btree records, but can&lt;br /&gt;
lie anywhere inside a single record. It also means that we can do&lt;br /&gt;
multiple extent allocations within one btree record to make optimal&lt;br /&gt;
use of the fragmented free space.&lt;br /&gt;
&lt;br /&gt;
It should be noted that this will probably have impact on some of the&lt;br /&gt;
inode cluster buffer mapping and clustering algorithms. It is not clear&lt;br /&gt;
exactly what impact yet, but certainly write clustering will be affected.&lt;br /&gt;
Fortunately we&#039;ll be able to detect the inodes that will have this problem&lt;br /&gt;
by the high bit in the inode number.&lt;br /&gt;
&lt;br /&gt;
== Inode Unlink ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If we turn to look at unlink and reclaim interactions, there are a few&lt;br /&gt;
optimisations that can be made.  Firstly, we don&#039;t need to do inode inactivation&lt;br /&gt;
in reclaim threads - these transactions can easily be pushed to a background&lt;br /&gt;
thread. This means that xfs_inactive would be little more than a vmtruncate()&lt;br /&gt;
call and queuing to a workqueue. This will substantially speed up the processing&lt;br /&gt;
of prune_icache() - we&#039;ll get inodes moved into reclaim much faster than we do&lt;br /&gt;
right now.&lt;br /&gt;
&lt;br /&gt;
This will have a noticable effect, though. When inodes are unlinked the space&lt;br /&gt;
consumed by those inodes may not be immediately freed - it will be returned as&lt;br /&gt;
the inodes are processed through the reclaim threads. This means that userspace&lt;br /&gt;
monitoring tools such as &#039;df&#039; may not immediately reflect the result of a&lt;br /&gt;
completed unlink operation. This will be a user visible change in behaviour,&lt;br /&gt;
though in most cases should not affect anyone and for those that it does affect&lt;br /&gt;
a &#039;sync&#039; should be sufficient to wait for the space to be returned.&lt;br /&gt;
&lt;br /&gt;
Now that inodes to be unlinked are out of general circulation, we can make the&lt;br /&gt;
unlinked path more complex. It is desirable to move the unlinked list from the&lt;br /&gt;
inode buffer to the inode core, but that has locking implications for incore&lt;br /&gt;
unlinked. Hence we really need background thread processing to enable this to&lt;br /&gt;
work (i.e. being able to requeue inodes for later processing). To ensure that&lt;br /&gt;
to overhead of this work is not a limiting factor, we will probably need&lt;br /&gt;
multiple workqueue processing threads for this.&lt;br /&gt;
&lt;br /&gt;
Moving the logging to the inode core enables two things - it allows us to keep&lt;br /&gt;
an in-memory copy of the unlinked list off the perag and that allows us to remove&lt;br /&gt;
xfs_inotobp(). The in-memory unlinked list means we don&#039;t have to read and&lt;br /&gt;
traverse the buffers every time we need to find the previous buffer to remove an&lt;br /&gt;
inode from the list, but it does mean we have to take the inode lock. If the&lt;br /&gt;
previous inode is locked, then we can&#039;t remove the inode from the unlinked list&lt;br /&gt;
so we must requeue it for this to occur at a later time.&lt;br /&gt;
&lt;br /&gt;
Combined with the changes to inode create, we effectively will only use the&lt;br /&gt;
inode buffer in the transaction subsystem for marking the region stale when&lt;br /&gt;
freeing an inode chunk from disk (i.e. the default noikeep configuration). If&lt;br /&gt;
we are using large inode allocation, we don&#039;t want to be freeing random inode&lt;br /&gt;
chunks - this will just leave us with fragmented inode regions and undo all the&lt;br /&gt;
good work that was done originally.&lt;br /&gt;
&lt;br /&gt;
To avoid this, we should not be freeing inode chunks as soon as they no longer&lt;br /&gt;
have any empty inodes in them. We should periodically scan the AGI btree&lt;br /&gt;
looking for contiguous chunks that have no inodes allocated in them, and then&lt;br /&gt;
freeing the large contiguous regions we find in one go. It is likely this can&lt;br /&gt;
be done in a single transaction; it&#039;s one extent to be freed, along with a&lt;br /&gt;
contiguous set of records to be removed from the AGI btree so should not&lt;br /&gt;
require logging much at all. Also, the background scanning could be triggered&lt;br /&gt;
by a number of different events - low space in an AG, a large number of free&lt;br /&gt;
inodes in an AG, etc - as it doesn&#039;t need to be done frequently. As a result&lt;br /&gt;
of the lack of frequency that this needs to be done, it can probably be&lt;br /&gt;
handled by a single thread or delayed workqueue.&lt;br /&gt;
&lt;br /&gt;
Further optimisations are possible here - if we rule that the AGI btree is the&lt;br /&gt;
sole place that inodes are marked free or in-use (with the exception of&lt;br /&gt;
unlinked inodes attached to the AGI lists), then we can avoid the need to&lt;br /&gt;
write back unlinked inodes or read newly created inodes from disk.  This would&lt;br /&gt;
require all inodes to effectively use a random generation number assigned at&lt;br /&gt;
create time as we would not be reading it from disk - writing/reading the current&lt;br /&gt;
generation number appears to be the only real reason for doing this I/O. This&lt;br /&gt;
would require extra checks to determine if an inode is unlinked - we&lt;br /&gt;
need to do an imap lookup rather than reading it and then checking it is&lt;br /&gt;
valid if it is not already in memory. Avoiding the I/O, however, will greatly speed&lt;br /&gt;
up create and remove workloads. Note: the impact of this on the bulkstat algorithm&lt;br /&gt;
has not been determined yet.&lt;br /&gt;
&lt;br /&gt;
One of the issues we need to consider with this background inactivation is that&lt;br /&gt;
we will be able to defer a large quantity of inactivation transactions so we are&lt;br /&gt;
going to need to be careful about how much we allow to be queued. Simple queue&lt;br /&gt;
depth throttling should be all that is needed to keep this under control.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Reclaim Optimizations ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now that we have efficient unlink, we&#039;ve got to handle the reclaim of all the&lt;br /&gt;
inodes that are now dead or simply not referenced. For inodes that are dirty,&lt;br /&gt;
we need to write them out to clean them. For inodes that are clean and not&lt;br /&gt;
unlinked, we need to compress them down for more compact storage. This involves&lt;br /&gt;
some CPU overhead, but it is worth noting that reclaiming of clean inodes&lt;br /&gt;
typically only occurs when we are under memory pressure.&lt;br /&gt;
&lt;br /&gt;
By compressing the XFS inode in this case, we are effectively reducing the&lt;br /&gt;
memory usage of the inode rather than freeing it directly. If we then get&lt;br /&gt;
another operation on that inode (e.g. the working set is slightly larger than&lt;br /&gt;
can be held in linux+XFS inode pairs, we avoid having to read the inode off&lt;br /&gt;
disk again - it simply gets uncompressed out of the cache. In essence we use&lt;br /&gt;
the compressed inode cache as an exclusive second level cache - it has higher&lt;br /&gt;
density than the primary cache and higher load latency and CPU overhead,&lt;br /&gt;
but it still avoids I/O in exactly the same manner as the primary cache.&lt;br /&gt;
&lt;br /&gt;
We cannot allow unrestricted build-up of reclaimable inodes - the memory they&lt;br /&gt;
consume will be large, so we should be aiming to compress reclaimable inodes as&lt;br /&gt;
soon as they are clean.  This will prevent buildup of memory consuming&lt;br /&gt;
uncompressed inodes that are not likely to be referenced again immediately.&lt;br /&gt;
&lt;br /&gt;
This clean inode reclaimation process can be accelerated by triggering reclaim&lt;br /&gt;
on inode I/O completion. If the inode is clean and reclaimable we should&lt;br /&gt;
trigger immediate reclaim processing of that inode.  This will mean that&lt;br /&gt;
reclaim of newly cleaned inodes will not get held up behind reclaim of dirty&lt;br /&gt;
inodes.&lt;br /&gt;
&lt;br /&gt;
For inodes that are unlinked, we can simply free them in reclaim as theƦ&lt;br /&gt;
are no longer in use. We don&#039;t want to poison the compressed cache with&lt;br /&gt;
unlinked inodes, nor do we need to because we can allocate new inodes&lt;br /&gt;
without incurring I/O.&lt;br /&gt;
&lt;br /&gt;
Still, we may end up with lots of inodes queued for reclaim. We may need&lt;br /&gt;
to implement a throttle mechanism to slow down the rate at which inodes&lt;br /&gt;
are queued for reclaimation in the situation where the reclaim process&lt;br /&gt;
is not able to keep up. It should be noted that if we parallelise inode&lt;br /&gt;
writeback we should also be able to parallelise inode reclaim via&lt;br /&gt;
the same mechanism, so the need for throttling may relatively low&lt;br /&gt;
if we can have multiple inodes under reclaim at once.&lt;br /&gt;
&lt;br /&gt;
It should be noted that complexity is exposed by interactions with concurrent&lt;br /&gt;
lookups, especially if we move to RCU locking on the radix tree. Firstly, we&lt;br /&gt;
need to be able to do an atomic swap of the compressed inode for the&lt;br /&gt;
uncompressed inode in the radix tree (and vice versa), to be able to tell them&lt;br /&gt;
apart (magic #), and to have atomic reference counts to ensure we can avoid use&lt;br /&gt;
after free situations when lookups race with compression or freeing.&lt;br /&gt;
&lt;br /&gt;
Secondly, with the complex unlink/reclaim interactions we will need to be&lt;br /&gt;
careful to detect inodes in the process of reclaim - the lookupp process&lt;br /&gt;
will need to do different things depending on the state of reclaim. Indeed,&lt;br /&gt;
we will need to be able to cancel reclaim of an unlinked inode if we try&lt;br /&gt;
to allocate it before it has been fully unlinked or reclaimed. The same&lt;br /&gt;
can be said for an inode in the process of being compressed - if we get&lt;br /&gt;
a lookup during the compression process, we want to return the existing&lt;br /&gt;
inode, not have to wait, re-allocate and uncompress it again. These&lt;br /&gt;
are all solvable issues - they just add complexity.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Accelerated Reclaim of buftarg Page Cache for Inodes ==&lt;br /&gt;
----------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
For single use inodes or even read-only inodes, we read them in, use them, then&lt;br /&gt;
reclaim them. With the compressed cache, they&#039;ll get compressed and live a lot&lt;br /&gt;
longer in memory. However, we also will have the inode cluster buffer pages&lt;br /&gt;
sitting in memory for some length of time after the inode was read in. This can&lt;br /&gt;
consume a large amount of memory that will never be used again, and does not&lt;br /&gt;
get reclaimed until they are purged from the LRU by the VM.  It would be&lt;br /&gt;
advantageous to accelerate the reclaim of these pages so that they do not build&lt;br /&gt;
up unneccessarily.&lt;br /&gt;
&lt;br /&gt;
One method we could use for this would be to introduce our own page LRUs into&lt;br /&gt;
the buftarg cache that we can reclaim from. This would allow us to sort pages&lt;br /&gt;
according to their contents into different LRUs and periodically reclaim pages&lt;br /&gt;
of specific types that were not referenced. This, however, would introduce a&lt;br /&gt;
fair amount of complexity into the buffer cache that doesn&#039;t currently exist.&lt;br /&gt;
Also, from a higher perspective, it makes the buffer cache a complex&lt;br /&gt;
part-buffer cache, part VM frankenstein.&lt;br /&gt;
&lt;br /&gt;
A better method would appear to be to leverage the delayed read queue&lt;br /&gt;
mechanism. This delayed read queue pins read buffers for a short period of&lt;br /&gt;
time, and then if they have not been referenced they get torn down.  If, as&lt;br /&gt;
part of this delayed read buffer teardown procedure we all free the backing&lt;br /&gt;
pages completely, we acheive the exact same result as having our own LRUs to&lt;br /&gt;
manage the page cache. This seems much simpler and a much more holistic&lt;br /&gt;
approach to solving the problem than implementing page LRUs.&lt;br /&gt;
&lt;br /&gt;
As an aside, we already have the mechanism in place to vary buffer aging based&lt;br /&gt;
on their type. The Irix buffer cache used this to great effect when under&lt;br /&gt;
memory pressure and the XFS code that configured it still exists in the Linux&lt;br /&gt;
code base. However, the Linux XFS buffer cache has never implemented any&lt;br /&gt;
mechanism to allow this functionality to be exploited. A delayed buffer reclaim&lt;br /&gt;
mechanism as described above could be greatly enhanced by making use of this&lt;br /&gt;
code in XFS.&lt;br /&gt;
&lt;br /&gt;
== Killing Bufferheads (a.k.a &amp;quot;Die, buggerheads, Die!&amp;quot;) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[This is not strictly about inode caching, but doesn&#039;t fit into&lt;br /&gt;
other areas of development as closely as it does to inode caching&lt;br /&gt;
optimisations.]&lt;br /&gt;
&lt;br /&gt;
XFS is extent based. The Linux page cache is block based. Hence for&lt;br /&gt;
every cached page in memory, we have to attach a structure for mapping&lt;br /&gt;
the blocks on that page back to to the on-disk location. In XFs, we also&lt;br /&gt;
use this to hold state for delayed allocation and unwritten extent blocks&lt;br /&gt;
so the generic code can do the right thing when necessary. We also&lt;br /&gt;
use it to avoid extent lookups at various times within the XFS I/O&lt;br /&gt;
path.&lt;br /&gt;
&lt;br /&gt;
However, this has a massive cost. While XFS might represent the&lt;br /&gt;
disk mapping of a 1GB extent in 24 bytes of memory, the page cache&lt;br /&gt;
requires 262,144 bufferheads (assuming 4k block size) to represent the&lt;br /&gt;
same mapping. That&#039;s roughly 14MB of memory neededtoo represent that.&lt;br /&gt;
&lt;br /&gt;
Chris Mason wrote an extent map representation for page cache state&lt;br /&gt;
and mappings for BTRFS; that code is mostly generic and could be&lt;br /&gt;
adapted to XFS. This would allow us to hold all the page cache state&lt;br /&gt;
in extent format and greatly reduce the memory overhead that it currently&lt;br /&gt;
has. The tradeoff is increased CPU overhead due to tree lookups where&lt;br /&gt;
structure lookups currently are used. Still, this has much lower&lt;br /&gt;
overhead than xfs_bmapi() based lookups, so the penalty is going to&lt;br /&gt;
be lower than if we did these lookups right now.&lt;br /&gt;
&lt;br /&gt;
If we make this change, we would then have three levels of extent&lt;br /&gt;
caching:&lt;br /&gt;
&lt;br /&gt;
	- the BMBT buffers&lt;br /&gt;
	- the XFS incore inode extent tree (iext*)&lt;br /&gt;
	- the page cache extent map tree&lt;br /&gt;
&lt;br /&gt;
Effectively, the XFS incore inode extent tree becomes redundant - all&lt;br /&gt;
the extent state it holds can be moved to the generic page cache tree&lt;br /&gt;
and we can do all our incore operations there. Our logging of changes&lt;br /&gt;
is based on the BMBT buffers, so getting rid of the iext layer would&lt;br /&gt;
not impact the transaction subsystem at all.&lt;br /&gt;
&lt;br /&gt;
Such integration with the generic code will also allow development&lt;br /&gt;
of generic writeback routines for delayed allocation, unwritten&lt;br /&gt;
extents, etc that are not specific to a given filesystem.&lt;br /&gt;
&lt;br /&gt;
== Demand Paging of Large Inode Extent Maps ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Currently the inode extent map is pinned  in memory until the inode is&lt;br /&gt;
reclaimed. Hence an inode with millions of extents will pin a large&lt;br /&gt;
amount of memory and this can cause serious issues in low memory&lt;br /&gt;
situations. Ideally we would like to be able to page the extent&lt;br /&gt;
map in and out once they get to a certain size to avoid this&lt;br /&gt;
problem. This feature requires more investigation before an overall&lt;br /&gt;
approach can be detailed here.&lt;br /&gt;
&lt;br /&gt;
It should be noted that if we move to an extent-based page cache mapping&lt;br /&gt;
tree, the associated extent state tree can be used to track sparse&lt;br /&gt;
regions. That is, regions of the extent map that are not in memory&lt;br /&gt;
can be easily represented and acceesses to an unread region can then&lt;br /&gt;
be used to trigger demand loading.&lt;br /&gt;
&lt;br /&gt;
== Food For Thought (Crazy Ideas) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If we are not using inode buffers for logging changes to inodes, we should&lt;br /&gt;
consider whether we need them at all. What benefit do the buffers bring us when&lt;br /&gt;
all we will use them for is read or write I/O?  Would it be better to go&lt;br /&gt;
straight to the buftarg page cache and do page based I/O via submit_bio()?&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=Improving_inode_Caching&amp;diff=2127</id>
		<title>Improving inode Caching</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=Improving_inode_Caching&amp;diff=2127"/>
		<updated>2010-12-23T03:37:35Z</updated>

		<summary type="html">&lt;p&gt;Dgc: /* Combining XFS and VFS inodes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Future Directions for XFS&lt;br /&gt;
&lt;br /&gt;
== Improving Inode Caching and Operation in XFS ==&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Thousand foot view:&lt;br /&gt;
&lt;br /&gt;
We want to drive inode lookup in a manner that is as parallel, scalable and low&lt;br /&gt;
overhead as possible. This means efficient indexing, lowering memory&lt;br /&gt;
consumption, simplifying the caching heirachy, removing duplication and&lt;br /&gt;
reducing/removing lock traffic.&lt;br /&gt;
&lt;br /&gt;
In addition, we want to provide a good foundation for simplifying inode I/O,&lt;br /&gt;
improving writeback clustering, preventing RMW of inode buffers under memory&lt;br /&gt;
pressure, reducing creation and deletion overhead and removing writeback of&lt;br /&gt;
unlogged changes completely.&lt;br /&gt;
&lt;br /&gt;
There are a variety of features in disconnected trees and patch sets that need&lt;br /&gt;
to be combined to acheive this - the basic structure needed to implement this is&lt;br /&gt;
already in mainline and that is the radix tree inode indexing.  Further&lt;br /&gt;
improvements are going to be based around this structure and using it&lt;br /&gt;
effectively to avoid needing other indexing mechanisms.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Discussion:&lt;br /&gt;
&lt;br /&gt;
== Combining XFS and VFS inodes ==&lt;br /&gt;
----------------------------&lt;br /&gt;
&lt;br /&gt;
Status: Done (October 2008)&lt;br /&gt;
&lt;br /&gt;
== Compressed Inode Cache ==&lt;br /&gt;
-----------------------------&lt;br /&gt;
&lt;br /&gt;
The XFs inode cache uses a lot of memory. We can avoid this problem by making&lt;br /&gt;
use of the compressed inode cache - only the active inodes are held in a&lt;br /&gt;
non-compressed form, hence most inodes will end up being cached in compressed&lt;br /&gt;
form rather than in the XFS/linux inode form.  The compressed form can reduce&lt;br /&gt;
the cached inode footprint to 200-300 bytes per inode instead of 1-1.1k that&lt;br /&gt;
they currently take on a 64bit system. Hence by moving to a compressed cache we&lt;br /&gt;
can greatly increase the number of inodes cached in a given amount of memory&lt;br /&gt;
which more that offsets any comparitive increase we will see from inodes in&lt;br /&gt;
reclaim. the compressed cache should really have a LRU and a shrinker as well&lt;br /&gt;
so that memory pressure will slowly trim it as memory demands occur. [Note:&lt;br /&gt;
this compressed cache is discussed further later on in the reclaim context.]&lt;br /&gt;
&lt;br /&gt;
== Fixed Inode Cache Size ==&lt;br /&gt;
&lt;br /&gt;
It is worth noting that for embedded systems and appliances it may be worth while allowing&lt;br /&gt;
the size of the caches to be fixed. Also, to prevent memory fragmentation&lt;br /&gt;
problems, we could simply allocate that memory to the compressed cache slab.&lt;br /&gt;
In effect, this would become a &#039;static slab&#039; in that it has a bound maximum&lt;br /&gt;
size and never frees and memory. When the cache is full, we reclaim an&lt;br /&gt;
object out of it for reuse - this could be done by triggering the shrinker&lt;br /&gt;
to reclaim from the LRU. This would prevent the compressed inode cache from&lt;br /&gt;
consuming excessive amounts of memory in tightly constrained evironments.&lt;br /&gt;
Such an extension to the slab caches does not look difficult to implement,&lt;br /&gt;
and would allow such customisation with minimal deviation from mainline code.&lt;br /&gt;
&lt;br /&gt;
== Bypassing the Linux Inode Cache ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With a larger number of cached inodes that the linux inode cache could possibly&lt;br /&gt;
hold, it makes sense to completely remove the linux inode cache from the lookup&lt;br /&gt;
path. That is, we do all our inode lookup based on the XFS cache, and if we find&lt;br /&gt;
a compressed inode we uncompress it and turn it into a combined linux+XFS inode.&lt;br /&gt;
If we also fast-path igrab() to avoid the inode_lock in the common case&lt;br /&gt;
(refcount &amp;gt; 0) then we will substantially reduce the traffic on the inode_lock.&lt;br /&gt;
&lt;br /&gt;
If we have not hashed the inode in the linux inode cache, we now have to take&lt;br /&gt;
care or tracking dirty inodes ourselves - unhashed inodes are not added to the&lt;br /&gt;
superblock dirty inode list by __mark_inode_dirty().  However, we do get a&lt;br /&gt;
callout (-&amp;gt;dirty_inode) that allows us to do this ourselves. We can use this&lt;br /&gt;
callout and a tag in the inode radix tree to track all dirty inodes, or even&lt;br /&gt;
just use the superblock list ourselves. Either way, we now have a mechanism that&lt;br /&gt;
allows us to track all dirty inodes our own way.&lt;br /&gt;
&lt;br /&gt;
Now that we can track dirty inodes ourselves, we can pretty much isolate&lt;br /&gt;
writeback of both data and inodes from the generic pdflush code. If we add a&lt;br /&gt;
hook high up in the pdflush path that simply passes us a writeback control&lt;br /&gt;
structure with the current writeback guidelines, we can do writeback within&lt;br /&gt;
those guidelines in the most optimal fashion for XFS.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Avoiding the Generic pdflush Code ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For pdflush driven writeback, we only want to write back data; all other inode&lt;br /&gt;
writeback should be driven from the AIL (our time ordered dirty metadata list)&lt;br /&gt;
or xfssyncd in a manner that is most optimal for XFS.&lt;br /&gt;
&lt;br /&gt;
Furthermore, if we implement our own pdflush method, we can parallelise it in&lt;br /&gt;
several ways. We can ensure that each filesystem has it&#039;s own flush thread or&lt;br /&gt;
thread pool, we can have a thread pool shared by all filesystems (like pdflush&lt;br /&gt;
currently operates), we can have a flush thread per inode radix tree, and so&lt;br /&gt;
one. The method of paralleisation is open for interpretation, but enabling&lt;br /&gt;
multiple flush threads to operate on a single filesystem is one of the necessary&lt;br /&gt;
requirements to avoid data writeback (and hence delayed allocation) being&lt;br /&gt;
limited to the throughput of a single CPU per filesystem.&lt;br /&gt;
&lt;br /&gt;
As it is, once data writeback is separated from inode writeback, we could&lt;br /&gt;
simply use pushing the AIL as a method of writing back metadata in the&lt;br /&gt;
background. There is no good reason for writing the inode immediately after&lt;br /&gt;
data if the inode is in the AIL - it will get written soon enough as the tail&lt;br /&gt;
of the AIL gets moved along. If we log all inode changes, then we&#039;ll be&lt;br /&gt;
unlikely to write the inode multiple times over it&#039;s dirty life-cycle as it&lt;br /&gt;
will continue to be moved forward in the AIL each time it is logged...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Improving Inode Writeback == &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To optimise inode writeback, we really need to reduce the impact of inode&lt;br /&gt;
buffer read-modify-write cycles. XFS is capable of caching far more inodes in&lt;br /&gt;
memory than it has buffer space available for, so RMW cycles during inode&lt;br /&gt;
writeback under memory pressure are quite common. Firstly, we want to avoid&lt;br /&gt;
blocking pdflush at all costs.  Secondly, we want to issue as much localised&lt;br /&gt;
readahead as possible in ascending offset order to allow both elevator merging&lt;br /&gt;
of readahead and as little seeking as possible. Finally, we want to issue all&lt;br /&gt;
the write cycles as close together as possible to allow the same elevator and&lt;br /&gt;
I/O optimisations to take place.&lt;br /&gt;
&lt;br /&gt;
To do this, firstly we need the non-blocking inode flush semantics to issue&lt;br /&gt;
readahead on buffers that are not up-to-date rather than reading them&lt;br /&gt;
synchronously. Inode writeback already has the interface to handle inodes that&lt;br /&gt;
weren&#039;t flushed - we return EAGAIN from xfs_iflush() and the higher inode&lt;br /&gt;
writeback layers handle this appropriately. It would be easy to add another&lt;br /&gt;
flag to pass down to the buffer layer to say &#039;issue but don&#039;t wait for any&lt;br /&gt;
read&#039;. If we use a radix tree traversal to issue readahead in such a manner,&lt;br /&gt;
we&#039;ll get ascending offset readahead being issued.&lt;br /&gt;
&lt;br /&gt;
One problem with this is that we can issue too much readahead and thrash the&lt;br /&gt;
cache. A possible solution to this is to make the readahead a &#039;delayed read&#039;&lt;br /&gt;
and on I/o completion add it to a queue that holds a reference on the buffer.&lt;br /&gt;
If a followup read occurs soon after, we remove it from the queue and drop that&lt;br /&gt;
reference. This prevents the buffer from being reclaimed in betwen the&lt;br /&gt;
readahead completing and the real read being issued. We should also issue this&lt;br /&gt;
delayed read on buffers that are in the cache so that they don&#039;t get reclaimed&lt;br /&gt;
to make room for the readahead.&lt;br /&gt;
&lt;br /&gt;
To prevent buildup of delayed read buffers, we can periodically purge them -&lt;br /&gt;
those that are older than a given age (say 5 seconds) can be removed from the&lt;br /&gt;
list and their reference dropped. This will free the buffer and allow it&#039;s&lt;br /&gt;
pages to be reclaimed.&lt;br /&gt;
&lt;br /&gt;
Once we have done the readahead pass, we can then do a modify and writeback&lt;br /&gt;
pass over all the inodes, knowing that there will be no read cycles to delay&lt;br /&gt;
this step. Once again, a radix tree traversal gives us ascending order&lt;br /&gt;
writeback and hence the modified buffers we send to the device will be in&lt;br /&gt;
optimal order for merging and minimal seek overhead.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Contiguous Inode Allocation ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To make optimal use of the radix tree cache and enable wide-scale clustering of&lt;br /&gt;
inode writeback across multiple clusters, we really need to ensure that inode&lt;br /&gt;
allocation occurs in large contiguous chunks on disk. Right now we only&lt;br /&gt;
allocate chunks of 64 inodes at a time; ideally we want to allocate a stripe&lt;br /&gt;
unit (or multiple of) full of inodes at a time. This would allow inode&lt;br /&gt;
writeback clustering to do full stripe writes to the underlying RAID if there&lt;br /&gt;
are dirty inodes spanning the entire stripe unit.&lt;br /&gt;
&lt;br /&gt;
The problem with doing this is that we don&#039;t want to introduce the latency of&lt;br /&gt;
creating megabytes of inodes when only one is needed for the current operation.&lt;br /&gt;
Hence we need to push the inode creation into a background thread and use that&lt;br /&gt;
to create contiguous inode chunks asynchronously. This moves the actual on-disk&lt;br /&gt;
allocation of inodes out of the normal create path; it should always be able to&lt;br /&gt;
find a free inode without doing on disk allocation. This will simplify the&lt;br /&gt;
create path by removing the allocate-on-disk-then-retry-the-create double&lt;br /&gt;
transaction that currently occurs.&lt;br /&gt;
&lt;br /&gt;
As an aside, we could preallocate a small amount of inodes in each AG (10-20MB&lt;br /&gt;
of inodes per AG?) without impacting mkfs time too greatly. This would allow&lt;br /&gt;
the filesystem to be used immediately on the first mount without triggering&lt;br /&gt;
lots of background allocation. This could alsobe done after the first mount&lt;br /&gt;
occurs, but that could interfere with typical benchmarking situations. Another&lt;br /&gt;
good reason for this preallocation is that it will help reduce xfs_repair&lt;br /&gt;
runtime for most common filesystem usages.&lt;br /&gt;
&lt;br /&gt;
One of the issues that the background create will cause is a substantial amount&lt;br /&gt;
of log traffic - every inode buffer initialised will be logged in whole. Hence&lt;br /&gt;
if we create a megabyte of inodes, we&#039;ll be causing a megabyte of log traffic&lt;br /&gt;
just for the inode buffers we&#039;ve initialised.  This is relatively simple to fix&lt;br /&gt;
- we don&#039;t log the buffer, we just log the fact that we need to initialise&lt;br /&gt;
inodes in a given range.  In recovery, when we see this transaction, then we&lt;br /&gt;
build the buffers, initialise them and write them out. Hence, we don&#039;t need to&lt;br /&gt;
log the buffers used to initialise the inodes.&lt;br /&gt;
&lt;br /&gt;
Also, we can use the background allocations to keep track of recently allocated&lt;br /&gt;
inode regions in the per-ag. Using that information to select the next inode to&lt;br /&gt;
be used rather than requiring btree searches on every create will greatly reduce&lt;br /&gt;
the CPU overhead of workloads that create lots of new inodes. It is not clear&lt;br /&gt;
whether a single background thread will be able to allocate enough inodes&lt;br /&gt;
to keep up with demand from the rest of the system - we may need multiple&lt;br /&gt;
threads for large configurations.&lt;br /&gt;
&lt;br /&gt;
== Single Block Inode Allocation ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
One of the big problems we have withe filesystems that are approaching&lt;br /&gt;
full is that it can be hard to find a large enough extent to hold 64 inodes.&lt;br /&gt;
We&#039;ve had ENOSPC errors on inode allocation reported on filesystems that&lt;br /&gt;
are only 85% full. This is a sign of free space fragmentation, and it&lt;br /&gt;
prevents inode allocation from succeeding. We could (and should) write&lt;br /&gt;
a free space defragmenter, but that does not solve the problem - it&#039;s&lt;br /&gt;
reactive, not preventative.&lt;br /&gt;
&lt;br /&gt;
The main problem we have is that XFS uses inode chunk size and alignment&lt;br /&gt;
to optimise inode number to disk location conversion. That is, the conversion&lt;br /&gt;
becomes a single set of shifts and masks instead of an AGI btree lookup.&lt;br /&gt;
This optimisation substantially reduces the CPU and I/O overhead of&lt;br /&gt;
inode lookups, but it does limit our flexibility. If we break the&lt;br /&gt;
alignment restriction, every lookup has to go back to a btree search.&lt;br /&gt;
Hence we really want to avoid breaking chunk alignment and size&lt;br /&gt;
rules.&lt;br /&gt;
&lt;br /&gt;
An approach to avoiding violation of this rule is to be able to determine which&lt;br /&gt;
index to look up when parsing the inode number. For example, we could use the&lt;br /&gt;
high bit of the inode number to indicate that it is located in a non-aligned&lt;br /&gt;
inode chunk and hence needs to be looked up in the btree. This would avoid&lt;br /&gt;
the lookup penalty for correctly aligned inode chunks.&lt;br /&gt;
&lt;br /&gt;
If we then redefine the meaning of the contents of the AGI btree record for&lt;br /&gt;
such inode chunks, we do not need a new index to keep these in. Effectively,&lt;br /&gt;
we need to add a bitmask to the record to indicate which blocks inside&lt;br /&gt;
the chunk can actually contain inodes. We still use aligned/sized records,&lt;br /&gt;
but mask out the sections that we are not allowed to allocate inodes in.&lt;br /&gt;
Effectively, this would allow sparse inode chunks. There may be limitations&lt;br /&gt;
on the resolution of sparseness depending on inode size and block size,&lt;br /&gt;
but for the common cases of 4k block size and 256 or 512 byte inodes I&lt;br /&gt;
think we can run a fully sparse mapping for each inode chunk.&lt;br /&gt;
&lt;br /&gt;
This would allow us to allocate inode extents of any alignment and size&lt;br /&gt;
that fits *inside* the existing alignment/size limitations. That is,&lt;br /&gt;
a single extent allocation could not span two btree records, but can&lt;br /&gt;
lie anywhere inside a single record. It also means that we can do&lt;br /&gt;
multiple extent allocations within one btree record to make optimal&lt;br /&gt;
use of the fragmented free space.&lt;br /&gt;
&lt;br /&gt;
It should be noted that this will probably have impact on some of the&lt;br /&gt;
inode cluster buffer mapping and clustering algorithms. It is not clear&lt;br /&gt;
exactly what impact yet, but certainly write clustering will be affected.&lt;br /&gt;
Fortunately we&#039;ll be able to detect the inodes that will have this problem&lt;br /&gt;
by the high bit in the inode number.&lt;br /&gt;
&lt;br /&gt;
== Inode Unlink ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If we turn to look at unlink and reclaim interactions, there are a few&lt;br /&gt;
optimisations that can be made.  Firstly, we don&#039;t need to do inode inactivation&lt;br /&gt;
in reclaim threads - these transactions can easily be pushed to a background&lt;br /&gt;
thread. This means that xfs_inactive would be little more than a vmtruncate()&lt;br /&gt;
call and queuing to a workqueue. This will substantially speed up the processing&lt;br /&gt;
of prune_icache() - we&#039;ll get inodes moved into reclaim much faster than we do&lt;br /&gt;
right now.&lt;br /&gt;
&lt;br /&gt;
This will have a noticable effect, though. When inodes are unlinked the space&lt;br /&gt;
consumed by those inodes may not be immediately freed - it will be returned as&lt;br /&gt;
the inodes are processed through the reclaim threads. This means that userspace&lt;br /&gt;
monitoring tools such as &#039;df&#039; may not immediately reflect the result of a&lt;br /&gt;
completed unlink operation. This will be a user visible change in behaviour,&lt;br /&gt;
though in most cases should not affect anyone and for those that it does affect&lt;br /&gt;
a &#039;sync&#039; should be sufficient to wait for the space to be returned.&lt;br /&gt;
&lt;br /&gt;
Now that inodes to be unlinked are out of general circulation, we can make the&lt;br /&gt;
unlinked path more complex. It is desirable to move the unlinked list from the&lt;br /&gt;
inode buffer to the inode core, but that has locking implications for incore&lt;br /&gt;
unlinked. Hence we really need background thread processing to enable this to&lt;br /&gt;
work (i.e. being able to requeue inodes for later processing). To ensure that&lt;br /&gt;
to overhead of this work is not a limiting factor, we will probably need&lt;br /&gt;
multiple workqueue processing threads for this.&lt;br /&gt;
&lt;br /&gt;
Moving the logging to the inode core enables two things - it allows us to keep&lt;br /&gt;
an in-memory copy of the unlinked list off the perag and that allows us to remove&lt;br /&gt;
xfs_inotobp(). The in-memory unlinked list means we don&#039;t have to read and&lt;br /&gt;
traverse the buffers every time we need to find the previous buffer to remove an&lt;br /&gt;
inode from the list, but it does mean we have to take the inode lock. If the&lt;br /&gt;
previous inode is locked, then we can&#039;t remove the inode from the unlinked list&lt;br /&gt;
so we must requeue it for this to occur at a later time.&lt;br /&gt;
&lt;br /&gt;
Combined with the changes to inode create, we effectively will only use the&lt;br /&gt;
inode buffer in the transaction subsystem for marking the region stale when&lt;br /&gt;
freeing an inode chunk from disk (i.e. the default noikeep configuration). If&lt;br /&gt;
we are using large inode allocation, we don&#039;t want to be freeing random inode&lt;br /&gt;
chunks - this will just leave us with fragmented inode regions and undo all the&lt;br /&gt;
good work that was done originally.&lt;br /&gt;
&lt;br /&gt;
To avoid this, we should not be freeing inode chunks as soon as they no longer&lt;br /&gt;
have any empty inodes in them. We should periodically scan the AGI btree&lt;br /&gt;
looking for contiguous chunks that have no inodes allocated in them, and then&lt;br /&gt;
freeing the large contiguous regions we find in one go. It is likely this can&lt;br /&gt;
be done in a single transaction; it&#039;s one extent to be freed, along with a&lt;br /&gt;
contiguous set of records to be removed from the AGI btree so should not&lt;br /&gt;
require logging much at all. Also, the background scanning could be triggered&lt;br /&gt;
by a number of different events - low space in an AG, a large number of free&lt;br /&gt;
inodes in an AG, etc - as it doesn&#039;t need to be done frequently. As a result&lt;br /&gt;
of the lack of frequency that this needs to be done, it can probably be&lt;br /&gt;
handled by a single thread or delayed workqueue.&lt;br /&gt;
&lt;br /&gt;
Further optimisations are possible here - if we rule that the AGI btree is the&lt;br /&gt;
sole place that inodes are marked free or in-use (with the exception of&lt;br /&gt;
unlinked inodes attached to the AGI lists), then we can avoid the need to&lt;br /&gt;
write back unlinked inodes or read newly created inodes from disk.  This would&lt;br /&gt;
require all inodes to effectively use a random generation number assigned at&lt;br /&gt;
create time as we would not be reading it from disk - writing/reading the current&lt;br /&gt;
generation number appears to be the only real reason for doing this I/O. This&lt;br /&gt;
would require extra checks to determine if an inode is unlinked - we&lt;br /&gt;
need to do an imap lookup rather than reading it and then checking it is&lt;br /&gt;
valid if it is not already in memory. Avoiding the I/O, however, will greatly speed&lt;br /&gt;
up create and remove workloads. Note: the impact of this on the bulkstat algorithm&lt;br /&gt;
has not been determined yet.&lt;br /&gt;
&lt;br /&gt;
One of the issues we need to consider with this background inactivation is that&lt;br /&gt;
we will be able to defer a large quantity of inactivation transactions so we are&lt;br /&gt;
going to need to be careful about how much we allow to be queued. Simple queue&lt;br /&gt;
depth throttling should be all that is needed to keep this under control.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Reclaim Optimizations ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now that we have efficient unlink, we&#039;ve got to handle the reclaim of all the&lt;br /&gt;
inodes that are now dead or simply not referenced. For inodes that are dirty,&lt;br /&gt;
we need to write them out to clean them. For inodes that are clean and not&lt;br /&gt;
unlinked, we need to compress them down for more compact storage. This involves&lt;br /&gt;
some CPU overhead, but it is worth noting that reclaiming of clean inodes&lt;br /&gt;
typically only occurs when we are under memory pressure.&lt;br /&gt;
&lt;br /&gt;
By compressing the XFS inode in this case, we are effectively reducing the&lt;br /&gt;
memory usage of the inode rather than freeing it directly. If we then get&lt;br /&gt;
another operation on that inode (e.g. the working set is slightly larger than&lt;br /&gt;
can be held in linux+XFS inode pairs, we avoid having to read the inode off&lt;br /&gt;
disk again - it simply gets uncompressed out of the cache. In essence we use&lt;br /&gt;
the compressed inode cache as an exclusive second level cache - it has higher&lt;br /&gt;
density than the primary cache and higher load latency and CPU overhead,&lt;br /&gt;
but it still avoids I/O in exactly the same manner as the primary cache.&lt;br /&gt;
&lt;br /&gt;
We cannot allow unrestricted build-up of reclaimable inodes - the memory they&lt;br /&gt;
consume will be large, so we should be aiming to compress reclaimable inodes as&lt;br /&gt;
soon as they are clean.  This will prevent buildup of memory consuming&lt;br /&gt;
uncompressed inodes that are not likely to be referenced again immediately.&lt;br /&gt;
&lt;br /&gt;
This clean inode reclaimation process can be accelerated by triggering reclaim&lt;br /&gt;
on inode I/O completion. If the inode is clean and reclaimable we should&lt;br /&gt;
trigger immediate reclaim processing of that inode.  This will mean that&lt;br /&gt;
reclaim of newly cleaned inodes will not get held up behind reclaim of dirty&lt;br /&gt;
inodes.&lt;br /&gt;
&lt;br /&gt;
For inodes that are unlinked, we can simply free them in reclaim as theƦ&lt;br /&gt;
are no longer in use. We don&#039;t want to poison the compressed cache with&lt;br /&gt;
unlinked inodes, nor do we need to because we can allocate new inodes&lt;br /&gt;
without incurring I/O.&lt;br /&gt;
&lt;br /&gt;
Still, we may end up with lots of inodes queued for reclaim. We may need&lt;br /&gt;
to implement a throttle mechanism to slow down the rate at which inodes&lt;br /&gt;
are queued for reclaimation in the situation where the reclaim process&lt;br /&gt;
is not able to keep up. It should be noted that if we parallelise inode&lt;br /&gt;
writeback we should also be able to parallelise inode reclaim via&lt;br /&gt;
the same mechanism, so the need for throttling may relatively low&lt;br /&gt;
if we can have multiple inodes under reclaim at once.&lt;br /&gt;
&lt;br /&gt;
It should be noted that complexity is exposed by interactions with concurrent&lt;br /&gt;
lookups, especially if we move to RCU locking on the radix tree. Firstly, we&lt;br /&gt;
need to be able to do an atomic swap of the compressed inode for the&lt;br /&gt;
uncompressed inode in the radix tree (and vice versa), to be able to tell them&lt;br /&gt;
apart (magic #), and to have atomic reference counts to ensure we can avoid use&lt;br /&gt;
after free situations when lookups race with compression or freeing.&lt;br /&gt;
&lt;br /&gt;
Secondly, with the complex unlink/reclaim interactions we will need to be&lt;br /&gt;
careful to detect inodes in the process of reclaim - the lookupp process&lt;br /&gt;
will need to do different things depending on the state of reclaim. Indeed,&lt;br /&gt;
we will need to be able to cancel reclaim of an unlinked inode if we try&lt;br /&gt;
to allocate it before it has been fully unlinked or reclaimed. The same&lt;br /&gt;
can be said for an inode in the process of being compressed - if we get&lt;br /&gt;
a lookup during the compression process, we want to return the existing&lt;br /&gt;
inode, not have to wait, re-allocate and uncompress it again. These&lt;br /&gt;
are all solvable issues - they just add complexity.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Accelerated Reclaim of buftarg Page Cache for Inodes ==&lt;br /&gt;
----------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
For single use inodes or even read-only inodes, we read them in, use them, then&lt;br /&gt;
reclaim them. With the compressed cache, they&#039;ll get compressed and live a lot&lt;br /&gt;
longer in memory. However, we also will have the inode cluster buffer pages&lt;br /&gt;
sitting in memory for some length of time after the inode was read in. This can&lt;br /&gt;
consume a large amount of memory that will never be used again, and does not&lt;br /&gt;
get reclaimed until they are purged from the LRU by the VM.  It would be&lt;br /&gt;
advantageous to accelerate the reclaim of these pages so that they do not build&lt;br /&gt;
up unneccessarily.&lt;br /&gt;
&lt;br /&gt;
One method we could use for this would be to introduce our own page LRUs into&lt;br /&gt;
the buftarg cache that we can reclaim from. This would allow us to sort pages&lt;br /&gt;
according to their contents into different LRUs and periodically reclaim pages&lt;br /&gt;
of specific types that were not referenced. This, however, would introduce a&lt;br /&gt;
fair amount of complexity into the buffer cache that doesn&#039;t currently exist.&lt;br /&gt;
Also, from a higher perspective, it makes the buffer cache a complex&lt;br /&gt;
part-buffer cache, part VM frankenstein.&lt;br /&gt;
&lt;br /&gt;
A better method would appear to be to leverage the delayed read queue&lt;br /&gt;
mechanism. This delayed read queue pins read buffers for a short period of&lt;br /&gt;
time, and then if they have not been referenced they get torn down.  If, as&lt;br /&gt;
part of this delayed read buffer teardown procedure we all free the backing&lt;br /&gt;
pages completely, we acheive the exact same result as having our own LRUs to&lt;br /&gt;
manage the page cache. This seems much simpler and a much more holistic&lt;br /&gt;
approach to solving the problem than implementing page LRUs.&lt;br /&gt;
&lt;br /&gt;
As an aside, we already have the mechanism in place to vary buffer aging based&lt;br /&gt;
on their type. The Irix buffer cache used this to great effect when under&lt;br /&gt;
memory pressure and the XFS code that configured it still exists in the Linux&lt;br /&gt;
code base. However, the Linux XFS buffer cache has never implemented any&lt;br /&gt;
mechanism to allow this functionality to be exploited. A delayed buffer reclaim&lt;br /&gt;
mechanism as described above could be greatly enhanced by making use of this&lt;br /&gt;
code in XFS.&lt;br /&gt;
&lt;br /&gt;
== Killing Bufferheads (a.k.a &amp;quot;Die, buggerheads, Die!&amp;quot;) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[This is not strictly about inode caching, but doesn&#039;t fit into&lt;br /&gt;
other areas of development as closely as it does to inode caching&lt;br /&gt;
optimisations.]&lt;br /&gt;
&lt;br /&gt;
XFS is extent based. The Linux page cache is block based. Hence for&lt;br /&gt;
every cached page in memory, we have to attach a structure for mapping&lt;br /&gt;
the blocks on that page back to to the on-disk location. In XFs, we also&lt;br /&gt;
use this to hold state for delayed allocation and unwritten extent blocks&lt;br /&gt;
so the generic code can do the right thing when necessary. We also&lt;br /&gt;
use it to avoid extent lookups at various times within the XFS I/O&lt;br /&gt;
path.&lt;br /&gt;
&lt;br /&gt;
However, this has a massive cost. While XFS might represent the&lt;br /&gt;
disk mapping of a 1GB extent in 24 bytes of memory, the page cache&lt;br /&gt;
requires 262,144 bufferheads (assuming 4k block size) to represent the&lt;br /&gt;
same mapping. That&#039;s roughly 14MB of memory neededtoo represent that.&lt;br /&gt;
&lt;br /&gt;
Chris Mason wrote an extent map representation for page cache state&lt;br /&gt;
and mappings for BTRFS; that code is mostly generic and could be&lt;br /&gt;
adapted to XFS. This would allow us to hold all the page cache state&lt;br /&gt;
in extent format and greatly reduce the memory overhead that it currently&lt;br /&gt;
has. The tradeoff is increased CPU overhead due to tree lookups where&lt;br /&gt;
structure lookups currently are used. Still, this has much lower&lt;br /&gt;
overhead than xfs_bmapi() based lookups, so the penalty is going to&lt;br /&gt;
be lower than if we did these lookups right now.&lt;br /&gt;
&lt;br /&gt;
If we make this change, we would then have three levels of extent&lt;br /&gt;
caching:&lt;br /&gt;
&lt;br /&gt;
	- the BMBT buffers&lt;br /&gt;
	- the XFS incore inode extent tree (iext*)&lt;br /&gt;
	- the page cache extent map tree&lt;br /&gt;
&lt;br /&gt;
Effectively, the XFS incore inode extent tree becomes redundant - all&lt;br /&gt;
the extent state it holds can be moved to the generic page cache tree&lt;br /&gt;
and we can do all our incore operations there. Our logging of changes&lt;br /&gt;
is based on the BMBT buffers, so getting rid of the iext layer would&lt;br /&gt;
not impact the transaction subsystem at all.&lt;br /&gt;
&lt;br /&gt;
Such integration with the generic code will also allow development&lt;br /&gt;
of generic writeback routines for delayed allocation, unwritten&lt;br /&gt;
extents, etc that are not specific to a given filesystem.&lt;br /&gt;
&lt;br /&gt;
== Demand Paging of Large Inode Extent Maps ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Currently the inode extent map is pinned  in memory until the inode is&lt;br /&gt;
reclaimed. Hence an inode with millions of extents will pin a large&lt;br /&gt;
amount of memory and this can cause serious issues in low memory&lt;br /&gt;
situations. Ideally we would like to be able to page the extent&lt;br /&gt;
map in and out once they get to a certain size to avoid this&lt;br /&gt;
problem. This feature requires more investigation before an overall&lt;br /&gt;
approach can be detailed here.&lt;br /&gt;
&lt;br /&gt;
It should be noted that if we move to an extent-based page cache mapping&lt;br /&gt;
tree, the associated extent state tree can be used to track sparse&lt;br /&gt;
regions. That is, regions of the extent map that are not in memory&lt;br /&gt;
can be easily represented and acceesses to an unread region can then&lt;br /&gt;
be used to trigger demand loading.&lt;br /&gt;
&lt;br /&gt;
== Food For Thought (Crazy Ideas) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If we are not using inode buffers for logging changes to inodes, we should&lt;br /&gt;
consider whether we need them at all. What benefit do the buffers bring us when&lt;br /&gt;
all we will use them for is read or write I/O?  Would it be better to go&lt;br /&gt;
straight to the buftarg page cache and do page based I/O via submit_bio()?&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=XFS_FAQ&amp;diff=2124</id>
		<title>XFS FAQ</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=XFS_FAQ&amp;diff=2124"/>
		<updated>2010-12-09T01:33:03Z</updated>

		<summary type="html">&lt;p&gt;Dgc: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Info from: [http://oss.sgi.com/projects/xfs/faq.html main XFS faq at SGI]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Many thanks to earlier maintainers of this document - Thomas Graichen and Seth Mos.&lt;br /&gt;
&lt;br /&gt;
== Q: Where can I find documentation about XFS? ==&lt;br /&gt;
&lt;br /&gt;
The SGI XFS project page http://oss.sgi.com/projects/xfs/ is the definitive reference. It contains pointers to whitepapers, books, articles, etc.&lt;br /&gt;
&lt;br /&gt;
You could also join the [[XFS_email_list_and_archives|XFS mailing list]] or the &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;#xfs&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039; IRC channel on &#039;&#039;irc.freenode.net&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Q: Where can I find documentation about ACLs? ==&lt;br /&gt;
&lt;br /&gt;
Andreas Gruenbacher maintains the Extended Attribute and POSIX ACL documentation for Linux at http://acl.bestbits.at/&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;acl(5)&#039;&#039;&#039; manual page is also quite extensive.&lt;br /&gt;
&lt;br /&gt;
== Q: Where can I find information about the internals of XFS? ==&lt;br /&gt;
&lt;br /&gt;
An [http://oss.sgi.com/projects/xfs/training/ SGI XFS Training course] aimed at developers, triage and support staff, and serious users has been in development. Parts of the course are clearly still incomplete, but there is enough content to be useful to a broad range of users.&lt;br /&gt;
&lt;br /&gt;
Barry Naujok has documented the [http://oss.sgi.com/projects/xfs/papers/xfs_filesystem_structure.pdf XFS ondisk format] which is a very useful reference.&lt;br /&gt;
&lt;br /&gt;
== Q: What partition type should I use for XFS on Linux? ==&lt;br /&gt;
&lt;br /&gt;
Linux native filesystem (83).&lt;br /&gt;
&lt;br /&gt;
== Q: What mount options does XFS have? ==&lt;br /&gt;
&lt;br /&gt;
There are a number of mount options influencing XFS filesystems - refer to the &#039;&#039;&#039;mount(8)&#039;&#039;&#039; manual page or the documentation in the kernel source tree itself ([http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/filesystems/xfs.txt;hb=HEAD Documentation/filesystems/xfs.txt])&lt;br /&gt;
&lt;br /&gt;
== Q: Is there any relation between the XFS utilities and the kernel version? ==&lt;br /&gt;
&lt;br /&gt;
No, there is no relation. Newer utilities tend to mainly have fixes and checks the previous versions might not have. New features are also added in a backward compatible way - if they are enabled via mkfs, an incapable (old) kernel will recognize that it does not understand the new feature, and refuse to mount the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Q: Does it run on platforms other than i386? ==&lt;br /&gt;
&lt;br /&gt;
XFS runs on all of the platforms that Linux supports. It is more tested on the more common platforms, especially the i386 family. Its also well tested on the IA64 platform since thats the platform SGI Linux products use.&lt;br /&gt;
&lt;br /&gt;
== Q: Quota: Do quotas work on XFS? ==&lt;br /&gt;
&lt;br /&gt;
Yes.&lt;br /&gt;
&lt;br /&gt;
To use quotas with XFS, you need to enable XFS quota support when you configure your kernel. You also need to specify quota support when mounting. You can get the Linux quota utilities at their sourceforge website [http://sourceforge.net/projects/linuxquota/  http://sourceforge.net/projects/linuxquota/] or use &#039;&#039;&#039;xfs_quota(8)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Q: Quota: What&#039;s project quota? ==&lt;br /&gt;
&lt;br /&gt;
The  project  quota  is a quota mechanism in XFS can be used to implement a form of directory tree quota, where a specified directory and all of the files and subdirectories below it (i.e. a tree) can be restricted to using a subset of the available space in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Q: Quota: Can group quota and project quota be used at the same time? ==&lt;br /&gt;
&lt;br /&gt;
No, project quota cannot be used with group quota at the same time. On the other hand user quota and project quota can be used simultaneously.&lt;br /&gt;
&lt;br /&gt;
== Q: Quota: Is umounting prjquota (project quota) enabled fs and mounting it again with grpquota (group quota) removing prjquota limits previously set from fs (and vice versa) ? ==&lt;br /&gt;
&lt;br /&gt;
To be answered.&lt;br /&gt;
&lt;br /&gt;
== Q: Are there any dump/restore tools for XFS? ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;xfsdump(8)&#039;&#039;&#039; and &#039;&#039;&#039;xfsrestore(8)&#039;&#039;&#039; are fully supported. The tape format is the same as on IRIX, so tapes are interchangeable between operating systems.&lt;br /&gt;
&lt;br /&gt;
== Q: Does LILO work with XFS? ==&lt;br /&gt;
&lt;br /&gt;
This depends on where you install LILO.&lt;br /&gt;
&lt;br /&gt;
Yes, for MBR (Master Boot Record) installations.&lt;br /&gt;
&lt;br /&gt;
No, for root partition installations because the XFS superblock is written at block zero, where LILO would be installed. This is to maintain compatibility with the IRIX on-disk format, and will not be changed.&lt;br /&gt;
&lt;br /&gt;
== Q: Does GRUB work with XFS? ==&lt;br /&gt;
&lt;br /&gt;
There is native XFS filesystem support for GRUB starting with version 0.91 and onward. Unfortunately, GRUB used to make incorrect assumptions about being able to read a block device image while a filesystem is mounted and actively being written to, which could cause intermittent problems when using XFS. This has reportedly since been fixed, and the 0.97 version (at least) of GRUB is apparently stable.&lt;br /&gt;
&lt;br /&gt;
== Q: Can XFS be used for a root filesystem? ==&lt;br /&gt;
&lt;br /&gt;
Yes, with one caveat: Linux does not support an external XFS journal for the root filesystem via the &amp;quot;rootflags=&amp;quot; kernel parameter. To use an external journal for the root filesystem in Linux, an init ramdisk must mount the root filesystem with explicit &amp;quot;logdev=&amp;quot; specified. [http://mindplusplus.wordpress.com/2008/07/27/scratching-an-i.html More information here.]&lt;br /&gt;
&lt;br /&gt;
== Q: Will I be able to use my IRIX XFS filesystems on Linux? ==&lt;br /&gt;
&lt;br /&gt;
Yes. The on-disk format of XFS is the same on IRIX and Linux. Obviously, you should back-up your data before trying to move it between systems. Filesystems must be &amp;quot;clean&amp;quot; when moved (i.e. unmounted). If you plan to use IRIX filesystems on Linux keep the following points in mind: the kernel needs to have SGI partition support enabled; there is no XLV support in Linux, so you are unable to read IRIX filesystems which use the XLV volume manager; also not all blocksizes available on IRIX are available on Linux (only blocksizes less than or equal to the pagesize of the architecture: 4k for i386, ppc, ... 8k for alpha, sparc, ... is possible for now). Make sure that the directory format is version 2 on the IRIX filesystems (this is the default since IRIX 6.5.5). Linux can only read v2 directories.&lt;br /&gt;
&lt;br /&gt;
== Q: Is there a way to make a XFS filesystem larger or smaller? ==&lt;br /&gt;
&lt;br /&gt;
You can &#039;&#039;NOT&#039;&#039; make a XFS partition smaller online. The only way to shrink is to do a complete dump, mkfs and restore.&lt;br /&gt;
&lt;br /&gt;
An XFS filesystem may be enlarged by using &#039;&#039;&#039;xfs_growfs(8)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
If using partitions, you need to have free space after this partition to do so. Remove partition, recreate it larger with the &#039;&#039;exact same&#039;&#039; starting point. Run &#039;&#039;&#039;xfs_growfs&#039;&#039;&#039; to make the partition larger. Note - editing partition tables is a dangerous pastime, so back up your filesystem before doing so.&lt;br /&gt;
&lt;br /&gt;
Using XFS filesystems on top of a volume manager makes this a lot easier.&lt;br /&gt;
&lt;br /&gt;
== Q: What information should I include when reporting a problem? ==&lt;br /&gt;
&lt;br /&gt;
Things to include are what version of XFS you are using, if this is a CVS version of what date and version of the kernel. If you have problems with userland packages please report the version of the package you are using.&lt;br /&gt;
&lt;br /&gt;
If the problem relates to a particular filesystem, the output from the &#039;&#039;&#039;xfs_info(8)&#039;&#039;&#039; command and any &#039;&#039;&#039;mount(8)&#039;&#039;&#039; options in use will also be useful to the developers.&lt;br /&gt;
&lt;br /&gt;
If you experience an oops, please run it through &#039;&#039;&#039;ksymoops&#039;&#039;&#039; so that it can be interpreted.&lt;br /&gt;
&lt;br /&gt;
If you have a filesystem that cannot be repaired, make sure you have xfsprogs 2.9.0 or later and run &#039;&#039;&#039;xfs_metadump(8)&#039;&#039;&#039; to capture the metadata (which obfuscates filenames and attributes to protect your privacy) and make the dump available for someone to analyse.&lt;br /&gt;
&lt;br /&gt;
== Q: Mounting an XFS filesystem does not work - what is wrong? ==&lt;br /&gt;
&lt;br /&gt;
If mount prints an error message something like:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
     mount: /dev/hda5 has wrong major or minor number&lt;br /&gt;
&lt;br /&gt;
you either do not have XFS compiled into the kernel (or you forgot to load the modules) or you did not use the &amp;quot;-t xfs&amp;quot; option on mount or the &amp;quot;xfs&amp;quot; option in &amp;lt;tt&amp;gt;/etc/fstab&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you get something like:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 mount: wrong fs type, bad option, bad superblock on /dev/sda1,&lt;br /&gt;
        or too many mounted file systems&lt;br /&gt;
&lt;br /&gt;
Refer to your system log file (&amp;lt;tt&amp;gt;/var/log/messages&amp;lt;/tt&amp;gt;) for a detailed diagnostic message from the kernel.&lt;br /&gt;
&lt;br /&gt;
== Q: Does the filesystem have an undelete capability? ==&lt;br /&gt;
&lt;br /&gt;
There is no undelete in XFS. However at least some XFS driver implementations does not wipe file information nodes completely so there are chance to recover files with specialized commercial software like [http://www.ufsexplorer.com/rdr_xfs.php Raise Data Recovery for XFS].&lt;br /&gt;
In this kind of XFS driver implementation it does not re-use directory entries immediately so there are chance to get back recently deleted files even with their real names.&lt;br /&gt;
&lt;br /&gt;
This applies to most recent Linux distributions, as well as to most popular NAS boxes that use embedded linux and XFS file system.&lt;br /&gt;
&lt;br /&gt;
Anyway, the best is to always keep backups.&lt;br /&gt;
&lt;br /&gt;
== Q: How can I backup a XFS filesystem and ACLs? ==&lt;br /&gt;
&lt;br /&gt;
You can backup a XFS filesystem with utilities like &#039;&#039;&#039;xfsdump(8)&#039;&#039;&#039; and standard &#039;&#039;&#039;tar(1)&#039;&#039;&#039; for standard files. If you want to backup ACLs you will need to use &#039;&#039;&#039;xfsdump&#039;&#039;&#039; or [http://www.bacula.org/en/dev-manual/Current_State_Bacula.html Bacula] (&amp;gt; version 3.1.4) or [http://rsync.samba.org/ rsync] (&amp;gt;= version 3.0.0) to backup ACLs and EAs. &#039;&#039;&#039;xfsdump&#039;&#039;&#039; can also be integrated with [http://www.amanda.org/ amanda(8)].&lt;br /&gt;
&lt;br /&gt;
== Q: I see applications returning error 990 or &amp;quot;Structure needs cleaning&amp;quot;, what is wrong? ==&lt;br /&gt;
&lt;br /&gt;
The error 990 stands for [http://oss.sgi.com/cgi-bin/gitweb.cgi?p=xfs/xfs.git;a=blob;f=fs/xfs/linux-2.6/xfs_linux.h#l145 EFSCORRUPTED] which usually means XFS has detected a filesystem metadata problem and has shut the filesystem down to prevent further damage. Also, since about June 2006, we [http://oss.sgi.com/cgi-bin/gitweb.cgi?p=xfs/xfs.git;a=commit;h=da2f4d679c8070ba5b6a920281e495917b293aa0 converted from EFSCORRUPTED/990 over to using EUCLEAN], &amp;quot;Structure needs cleaning.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The cause can be pretty much anything, unfortunately - filesystem, virtual memory manager, volume manager, device driver, or hardware.&lt;br /&gt;
&lt;br /&gt;
There should be a detailed console message when this initially happens. The messages have important information giving hints to developers as to the earliest point that a problem was detected. It is there to protect your data.&lt;br /&gt;
&lt;br /&gt;
You can use xfs_check and xfs_repair to remedy the problem (with the file system unmounted).&lt;br /&gt;
&lt;br /&gt;
== Q: Why do I see binary NULLS in some files after recovery when I unplugged the power? ==&lt;br /&gt;
&lt;br /&gt;
Update: This issue has been addressed with a CVS fix on the 29th March 2007 and merged into mainline on 8th May 2007 for 2.6.22-rc1.&lt;br /&gt;
&lt;br /&gt;
XFS journals metadata updates, not data updates. After a crash you are supposed to get a consistent filesystem which looks like the state sometime shortly before the crash, NOT what the in memory image looked like the instant before the crash.&lt;br /&gt;
&lt;br /&gt;
Since XFS does not write data out immediately unless you tell it to with fsync, an O_SYNC or O_DIRECT open (the same is true of other filesystems), you are looking at an inode which was flushed out, but whose data was not. Typically you&#039;ll find that the inode is not taking any space since all it has is a size but no extents allocated (try examining the file with the &#039;&#039;&#039;xfs_bmap(8)&#039;&#039;&#039; command).&lt;br /&gt;
&lt;br /&gt;
== Q: What is the problem with the write cache on journaled filesystems? ==&lt;br /&gt;
&lt;br /&gt;
Many drives use a write back cache in order to speed up the performance of writes.  However, there are conditions such as power failure when the write cache memory is never flushed to the actual disk.  Further, the drive can de-stage data from the write cache to the platters in any order that it chooses.  This causes problems for XFS and journaled filesystems in general because they rely on knowing when a write has completed to the disk. They need to know that the log information has made it to disk before allowing metadata to go to disk.  When the metadata makes it to disk then the transaction can effectively be deleted from the log resulting in movement of the tail of the log and thus freeing up some log space. So if the writes never make it to the physical disk, then the ordering is violated and the log and metadata can be lost, resulting in filesystem corruption.&lt;br /&gt;
&lt;br /&gt;
With hard disk cache sizes of currently (Jan 2009) up to 32MB that can be a lot of valuable information.  In a RAID with 8 such disks these adds to 256MB, and the chance of having filesystem metadata in the cache is so high that you have a very high chance of big data losses on a power outage.&lt;br /&gt;
&lt;br /&gt;
With a single hard disk and barriers turned on (on=default), the drive write cache is flushed before and after a barrier is issued.  A powerfail &amp;quot;only&amp;quot; loses data in the cache but no essential ordering is violated, and corruption will not occur.&lt;br /&gt;
&lt;br /&gt;
With a RAID controller with battery backed controller cache and cache in write back mode, you should turn off barriers - they are unnecessary in this case, and if the controller honors the cache flushes, it will be harmful to performance.  But then you *must* disable the individual hard disk write cache in order to ensure to keep the filesystem intact after a power failure. The method for doing this is different for each RAID controller. See the section about RAID controllers below.&lt;br /&gt;
&lt;br /&gt;
== Q: How can I tell if I have the disk write cache enabled? ==&lt;br /&gt;
&lt;br /&gt;
For SCSI/SATA:&lt;br /&gt;
&lt;br /&gt;
* Look in dmesg(8) output for a driver line, such as:&amp;lt;br /&amp;gt; &amp;quot;SCSI device sda: drive cache: write back&amp;quot;&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;# sginfo -c /dev/sda | grep -i &#039;write cache&#039; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For PATA/SATA (although for SATA this only works on a recent kernel with ATA command passthrough):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;# hdparm -I /dev/sda&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; and look under &amp;quot;Enabled Supported&amp;quot; for &amp;quot;Write cache&amp;quot;&lt;br /&gt;
&lt;br /&gt;
For RAID controllers:&lt;br /&gt;
&lt;br /&gt;
* See the section about RAID controllers below&lt;br /&gt;
&lt;br /&gt;
== Q: How can I address the problem with the disk write cache? ==&lt;br /&gt;
&lt;br /&gt;
=== Disabling the disk write back cache. ===&lt;br /&gt;
&lt;br /&gt;
For SATA/PATA(IDE): (although for SATA this only works on a recent kernel with ATA command passthrough):&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;# hdparm -W0 /dev/sda&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; # hdparm -W0 /dev/hda&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;# blktool /dev/sda wcache off&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; # blktool /dev/hda wcache off&lt;br /&gt;
&lt;br /&gt;
For SCSI:&lt;br /&gt;
&lt;br /&gt;
* Using sginfo(8) which is a little tedious&amp;lt;br /&amp;gt; It takes 3 steps. For example:&lt;br /&gt;
*# &amp;lt;nowiki&amp;gt;#sginfo -c /dev/sda&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; which gives a list of attribute names and values&lt;br /&gt;
*# &amp;lt;nowiki&amp;gt;#sginfo -cX /dev/sda&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; which gives an array of cache values which you must match up with from step 1, e.g.&amp;lt;br /&amp;gt; 0 0 0 1 0 1 0 0 0 0 65535 0 65535 65535 1 0 0 0 3 0 0&lt;br /&gt;
*# &amp;lt;nowiki&amp;gt;#sginfo -cXR /dev/sda 0 0 0 1 0 0 0 0 0 0 65535 0 65535 65535 1 0 0 0 3 0 0&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; allows you to reset the value of the cache attributes.&lt;br /&gt;
&lt;br /&gt;
For RAID controllers:&lt;br /&gt;
&lt;br /&gt;
* See the section about RAID controllers below&lt;br /&gt;
&lt;br /&gt;
This disabling is kept persistent for a SCSI disk. However, for a SATA/PATA disk this needs to be done after every reset as it will reset back to the default of the write cache enabled. And a reset can happen after reboot or on error recovery of the drive. This makes it rather difficult to guarantee that the write cache is maintained as disabled.&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using an external log. ===&lt;br /&gt;
&lt;br /&gt;
Some people have considered the idea of using an external log on a separate drive with the write cache disabled and the rest of the file system on another disk with the write cache enabled. However, that will &#039;&#039;&#039;not&#039;&#039;&#039; solve the problem. For example, the tail of the log is moved when we are notified that a metadata write is completed to disk and we won&#039;t be able to guarantee that if the metadata is on a drive with the write cache enabled.&lt;br /&gt;
&lt;br /&gt;
In fact using an external log will disable XFS&#039; write barrier support.&lt;br /&gt;
&lt;br /&gt;
=== Write barrier support. ===&lt;br /&gt;
&lt;br /&gt;
Write barrier support is enabled by default in XFS since kernel version 2.6.17. It is disabled by mounting the filesystem with &amp;quot;nobarrier&amp;quot;. Barrier support will flush the write back cache at the appropriate times (such as on XFS log writes). This is generally the recommended solution, however, you should check the system logs to ensure it was successful. Barriers will be disabled and reported in the log if any of the 3 scenarios occurs:&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;Disabling barriers, not supported with external log device&amp;quot;&lt;br /&gt;
* &amp;quot;Disabling barriers, not supported by the underlying device&amp;quot;&lt;br /&gt;
* &amp;quot;Disabling barriers, trial barrier write failed&amp;quot;&lt;br /&gt;
&lt;br /&gt;
If the filesystem is mounted with an external log device then we currently don&#039;t support flushing to the data and log devices (this may change in the future). If the driver tells the block layer that the device does not support write cache flushing with the write cache enabled then it will report that the device doesn&#039;t support it. And finally we will actually test out a barrier write on the superblock and test its error state afterwards, reporting if it fails.&lt;br /&gt;
&lt;br /&gt;
== Q. Should barriers be enabled with storage which has a persistent write cache? ==&lt;br /&gt;
&lt;br /&gt;
Many hardware RAID have a persistent write cache which preserves it across power failure, interface resets, system crashes, etc. Using write barriers in this instance is not recommended and will in fact lower performance. Therefore, it is recommended to turn off the barrier support and mount the filesystem with &amp;quot;nobarrier&amp;quot;. But take care about the hard disk write cache, which should be off.&lt;br /&gt;
&lt;br /&gt;
== Q. Which settings does my RAID controller need ? ==&lt;br /&gt;
&lt;br /&gt;
It&#039;s hard to tell because there are so many controllers. Please consult your RAID controller documentation to determine how to change these settings, but we try to give an overview here:&lt;br /&gt;
&lt;br /&gt;
Real RAID controllers (not those found onboard of mainboards) normally have a battery backed cache (or an [http://en.wikipedia.org/wiki/Electric_double-layer_capacitor ultracapacitor] + flash memory &amp;quot;[http://www.tweaktown.com/articles/2800/adaptec_zero_maintenance_cache_protection_explained/ zero maintenance cache]&amp;quot;) which is used for buffering writes to improve speed. Even if it&#039;s battery backed, the individual hard disk write caches need to be turned off, as they are not protected from a powerfail and will just lose all contents in that case.&lt;br /&gt;
&lt;br /&gt;
* onboard RAID controllers: there are so many different types it&#039;s hard to tell. Generally, those controllers have no cache, but let the hard disk write cache on. That can lead to the bad situation that after a powerfail with RAID-1 when only parts of the disk cache have been written, the controller doesn&#039;t even see that the disks are out of sync, as the disks can resort cached blocks and might have saved the superblock info, but then lost different data contents. So, turn off disk write caches before using the RAID function.&lt;br /&gt;
&lt;br /&gt;
* 3ware: /cX/uX set cache=off, see http://www.3ware.com/support/UserDocs/CLIGuide-9.5.1.1.pdf , page 86&lt;br /&gt;
&lt;br /&gt;
* Adaptec: allows setting individual drives cache&lt;br /&gt;
arcconf setcache &amp;lt;disk&amp;gt; wb|wt&lt;br /&gt;
wb=write back, which means write cache on, wt=write through, which means write cache off. So &amp;quot;wt&amp;quot; should be chosen.&lt;br /&gt;
&lt;br /&gt;
* Areca: In archttp under &amp;quot;System Controls&amp;quot; -&amp;gt; &amp;quot;System Configuration&amp;quot; there&#039;s the option &amp;quot;Disk Write Cache Mode&amp;quot; (defaults &amp;quot;Auto&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Off&amp;quot;: disk write cache is turned off&lt;br /&gt;
&lt;br /&gt;
&amp;quot;On&amp;quot;: disk write cache is enabled, this is not save for your data but fast&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Auto&amp;quot;: If you use a BBM (battery backup module, which you really should use if you care about your data), the controller automatically turns disk writes off, to protect your data. In case no BBM is attached, the controller switches to &amp;quot;On&amp;quot;, because neither controller cache nor disk cache is save so you don&#039;t seem to care about your data and just want high speed (which you get then).&lt;br /&gt;
&lt;br /&gt;
That&#039;s a very sensible default so you can let it &amp;quot;Auto&amp;quot; or enforce &amp;quot;Off&amp;quot; to be sure.&lt;br /&gt;
&lt;br /&gt;
* LSI MegaRAID: allows setting individual disks cache:&lt;br /&gt;
MegaCli -AdpCacheFlush -aN|-a0,1,2|-aALL -EnDskCache|DisDskCache&lt;br /&gt;
&lt;br /&gt;
* Xyratex: from the docs: &amp;quot;Write cache includes the disk drive cache and controller cache.&amp;quot;. So that means you can only set the drive caches and the unit caches together. To protect your data, turn it off, but write performance will suffer badly as also the controller write cache is disabled.&lt;br /&gt;
&lt;br /&gt;
== Q: Which settings are best with virtualization like VMware, XEN, qemu? ==&lt;br /&gt;
&lt;br /&gt;
The biggest problem is that those products seem to also virtualize disk &lt;br /&gt;
writes in a way that even barriers don&#039;t work anymore, which means even &lt;br /&gt;
a fsync is not reliable. Tests confirm that unplugging the power from &lt;br /&gt;
such a system even with RAID controller with battery backed cache and &lt;br /&gt;
hard disk cache turned off (which is save on a normal host) you can &lt;br /&gt;
destroy a database within the virtual machine (client, domU whatever you &lt;br /&gt;
call it).&lt;br /&gt;
&lt;br /&gt;
In qemu you can specify cache=off on the line specifying the virtual &lt;br /&gt;
disk. For others information is missing.&lt;br /&gt;
&lt;br /&gt;
== Q: What is the issue with directory corruption in Linux 2.6.17? ==&lt;br /&gt;
&lt;br /&gt;
In the Linux kernel 2.6.17 release a subtle bug was accidentally introduced into the XFS directory code by some &amp;quot;sparse&amp;quot; endian annotations. This bug was sufficiently uncommon (it only affects a certain type of format change, in Node or B-Tree format directories, and only in certain situations) that it was not detected during our regular regression testing, but it has been observed in the wild by a number of people now.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Update: the fix is included in 2.6.17.7 and later kernels.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
To add insult to injury, &#039;&#039;&#039;xfs_repair(8)&#039;&#039;&#039; is currently not correcting these directories on detection of this corrupt state either. This &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; issue is actively being worked on, and a fixed version will be available shortly.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Update: a fixed &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; is now available; version 2.8.10 or later of the xfsprogs package contains the fixed version.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
No other kernel versions are affected. However, using a corrupt filesystem on other kernels can still result in the filesystem being shutdown if the problem has not been rectified (on disk), making it seem like other kernels are affected.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;xfs_check&#039;&#039;&#039; tool, or &#039;&#039;&#039;xfs_repair -n&#039;&#039;&#039;, should be able to detect any directory corruption.&lt;br /&gt;
&lt;br /&gt;
Until a fixed &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; binary is available, one can make use of the &#039;&#039;&#039;xfs_db(8)&#039;&#039;&#039; command to mark the problem directory for removal (see the example below). A subsequent &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; invocation will remove the directory and move all contents into &amp;quot;lost+found&amp;quot;, named by inode number (see second example on how to map inode number to directory entry name, which needs to be done _before_ removing the directory itself). The inode number of the corrupt directory is included in the shutdown report issued by the kernel on detection of directory corruption. Using that inode number, this is how one would ensure it is removed:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 # xfs_db -x /dev/sdXXX&lt;br /&gt;
 xfs_db&amp;amp;gt; inode NNN&lt;br /&gt;
 xfs_db&amp;amp;gt; print&lt;br /&gt;
 core.magic = 0x494e&lt;br /&gt;
 core.mode = 040755&lt;br /&gt;
 core.version = 2&lt;br /&gt;
 core.format = 3 (btree)&lt;br /&gt;
 ...&lt;br /&gt;
 xfs_db&amp;amp;gt; write core.mode 0&lt;br /&gt;
 xfs_db&amp;amp;gt; quit&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A subsequent &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; will clear the directory, and add new entries (named by inode number) in lost+found.&lt;br /&gt;
&lt;br /&gt;
The easiest way to map inode numbers to full paths is via &#039;&#039;&#039;xfs_ncheck(8)&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;: &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 # xfs_ncheck -i 14101 -i 14102 /dev/sdXXX&lt;br /&gt;
       14101 full/path/mumble_fratz_foo_bar_1495&lt;br /&gt;
       14102 full/path/mumble_fratz_foo_bar_1494&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Should this not work, we can manually map inode numbers in B-Tree format directory by taking the following steps:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 # xfs_db -x /dev/sdXXX&lt;br /&gt;
 xfs_db&amp;amp;gt; inode NNN&lt;br /&gt;
 xfs_db&amp;amp;gt; print&lt;br /&gt;
 core.magic = 0x494e&lt;br /&gt;
 ...&lt;br /&gt;
 next_unlinked = null&lt;br /&gt;
 u.bmbt.level = 1&lt;br /&gt;
 u.bmbt.numrecs = 1&lt;br /&gt;
 u.bmbt.keys[1] = [startoff] 1:[0]&lt;br /&gt;
 u.bmbt.ptrs[1] = 1:3628&lt;br /&gt;
 xfs_db&amp;amp;gt; fsblock 3628&lt;br /&gt;
 xfs_db&amp;amp;gt; type bmapbtd&lt;br /&gt;
 xfs_db&amp;amp;gt; print&lt;br /&gt;
 magic = 0x424d4150&lt;br /&gt;
 level = 0&lt;br /&gt;
 numrecs = 19&lt;br /&gt;
 leftsib = null&lt;br /&gt;
 rightsib = null&lt;br /&gt;
 recs[1-19] = [startoff,startblock,blockcount,extentflag]&lt;br /&gt;
        1:[0,3088,4,0] 2:[4,3128,8,0] 3:[12,3308,4,0] 4:[16,3360,4,0]&lt;br /&gt;
        5:[20,3496,8,0] 6:[28,3552,8,0] 7:[36,3624,4,0] 8:[40,3633,4,0]&lt;br /&gt;
        9:[44,3688,8,0] 10:[52,3744,4,0] 11:[56,3784,8,0]&lt;br /&gt;
        12:[64,3840,8,0] 13:[72,3896,4,0] 14:[33554432,3092,4,0]&lt;br /&gt;
        15:[33554436,3488,8,0] 16:[33554444,3629,4,0]&lt;br /&gt;
        17:[33554448,3748,4,0] 18:[33554452,3900,4,0]&lt;br /&gt;
        19:[67108864,3364,4,0]&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At this point we are looking at the extents that hold all of the directory information. There are three types of extent here, we have the data blocks (extents 1 through 13 above), then the leaf blocks (extents 14 through 18), then the freelist blocks (extent 19 above). The jumps in the first field (start offset) indicate our progression through each of the three types. For recovering file names, we are only interested in the data blocks, so we can now feed those offset numbers into the &#039;&#039;&#039;xfs_db&#039;&#039;&#039; dblock command. So, for the fifth extent - 5:[20,3496,8,0] - listed above:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
 xfs_db&amp;amp;gt; dblock 20&lt;br /&gt;
 xfs_db&amp;amp;gt; print&lt;br /&gt;
 dhdr.magic = 0x58443244&lt;br /&gt;
 dhdr.bestfree[0].offset = 0&lt;br /&gt;
 dhdr.bestfree[0].length = 0&lt;br /&gt;
 dhdr.bestfree[1].offset = 0&lt;br /&gt;
 dhdr.bestfree[1].length = 0&lt;br /&gt;
 dhdr.bestfree[2].offset = 0&lt;br /&gt;
 dhdr.bestfree[2].length = 0&lt;br /&gt;
 du[0].inumber = 13937&lt;br /&gt;
 du[0].namelen = 25&lt;br /&gt;
 du[0].name = &amp;quot;mumble_fratz_foo_bar_1595&amp;quot;&lt;br /&gt;
 du[0].tag = 0x10&lt;br /&gt;
 du[1].inumber = 13938&lt;br /&gt;
 du[1].namelen = 25&lt;br /&gt;
 du[1].name = &amp;quot;mumble_fratz_foo_bar_1594&amp;quot;&lt;br /&gt;
 du[1].tag = 0x38&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
So, here we can see that inode number 13938 matches up with name &amp;quot;mumble_fratz_foo_bar_1594&amp;quot;. Iterate through all the extents, and extract all the name-to-inode-number mappings you can, as these will be useful when looking at &amp;quot;lost+found&amp;quot; (once &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; has removed the corrupt directory).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Q: Why does my &amp;gt; 2TB XFS partition disappear when I reboot ? ==&lt;br /&gt;
&lt;br /&gt;
Strictly speaking this is not an XFS problem.&lt;br /&gt;
&lt;br /&gt;
To support &amp;gt; 2TB partitions you need two things: a kernel that supports large block devices (&amp;lt;tt&amp;gt;CONFIG_LBD=y&amp;lt;/tt&amp;gt;) and a partition table format that can hold large partitions.  The default DOS partition tables don&#039;t.  The best partition format for&lt;br /&gt;
&amp;gt; 2TB partitions is the EFI GPT format (&amp;lt;tt&amp;gt;CONFIG_EFI_PARTITION=y&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Without CONFIG_LBD=y you can&#039;t even create the filesystem, but without &amp;lt;tt&amp;gt;CONFIG_EFI_PARTITION=y&amp;lt;/tt&amp;gt; it works fine until you reboot at which point the partition will disappear.  Note that you need to enable the &amp;lt;tt&amp;gt;CONFIG_PARTITION_ADVANCED&amp;lt;/tt&amp;gt; option before you can set &amp;lt;tt&amp;gt;CONFIG_EFI_PARTITION=y&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Q: Why do I receive &amp;lt;tt&amp;gt;No space left on device&amp;lt;/tt&amp;gt; after &amp;lt;tt&amp;gt;xfs_growfs&amp;lt;/tt&amp;gt;? ==&lt;br /&gt;
&lt;br /&gt;
After [http://oss.sgi.com/pipermail/xfs/2009-January/039828.html growing a XFS filesystem], df(1) would show enough free space but attempts to write to the filesystem result in -ENOSPC. To fix this, [http://oss.sgi.com/pipermail/xfs/2009-January/039835.html Dave Chinner advised]:&lt;br /&gt;
&lt;br /&gt;
  The only way to fix this is to move data around to free up space&lt;br /&gt;
  below 1TB. Find your oldest data (i.e. that was around before even&lt;br /&gt;
  the first grow) and move it off the filesystem (move, not copy).&lt;br /&gt;
  Then if you copy it back on, the data blocks will end up above 1TB&lt;br /&gt;
  and that should leave you with plenty of space for inodes below 1TB.&lt;br /&gt;
  &lt;br /&gt;
  A complete dump and restore will also fix the problem ;)&lt;br /&gt;
&lt;br /&gt;
Also, you can add &#039;inode64&#039; to your mount options to allow inodes to live above 1TB.&lt;br /&gt;
&lt;br /&gt;
== Q: Is using noatime or/and nodiratime at mount time giving any performance benefits in xfs (or not using them performance decrease)? ==&lt;br /&gt;
&lt;br /&gt;
The default atime behaviour is relatime, which has almost no overhead compared to noatime but still maintains sane atime values. All Linux filesystems use this as the default now (since around 2.6.30), but XFS has used relatime-like behaviour since 2006, so no-one should really need to ever use noatime on XFS for performance reasons. &lt;br /&gt;
&lt;br /&gt;
Also, noatime implies nodiratime, so there is never a need to specify nodiratime when noatime is also specified.&lt;br /&gt;
&lt;br /&gt;
== Q: How to get around a bad inode repair is unable to clean up ==&lt;br /&gt;
&lt;br /&gt;
The trick is go in with xfs_db and mark the inode as a deleted, which will cause repair to clean it up and finish the remove process.&lt;br /&gt;
&lt;br /&gt;
  xfs_db -x -c &#039;inode XXX&#039; -c &#039;write core.nextents 0&#039; -c &#039;write core.size 0&#039; /dev/hdXX&lt;br /&gt;
&lt;br /&gt;
== Q: How to calculate the correct sunit,swidth values for optimal performance ==&lt;br /&gt;
&lt;br /&gt;
XFS allows to optimize for a given RAID stripe size and number of disks via mount options. The calculation of these values is quite simple:&lt;br /&gt;
&lt;br /&gt;
  su = &amp;lt;RAID controllers stripe size in BYTES (or KiBytes when used with k)&amp;gt;&lt;br /&gt;
  sw = &amp;lt;# of data disks&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So if your RAID controller has a stripe size of 64KB, and you have a RAID-6 with 8 disks, use&lt;br /&gt;
&lt;br /&gt;
  su = 64k&lt;br /&gt;
  sw = 6 (RAID-6 of 8 disks has 6 data disks)&lt;br /&gt;
&lt;br /&gt;
A RAID stripe size of 256KB with a RAID-10 over 16 disks should use&lt;br /&gt;
&lt;br /&gt;
  su = 256k&lt;br /&gt;
  sw = 8 (RAID-10 of 16 disks has 8 data disks)&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can use &amp;quot;sunit&amp;quot; instead of &amp;quot;su&amp;quot;, but then the value means &amp;quot;number of 512B sectors&amp;quot;, and you *must* use &amp;quot;swidth&amp;quot; then as &amp;quot;number of 512B sectors&amp;quot; then as well!&lt;br /&gt;
&lt;br /&gt;
Please be aware that when xfs_info or mkfs.xfs report the sunit/swidth values, they use a different unit size than above.  Whereas sunit and swidth are first specified in 512B sectors, xfs_info and mkfs.xfs report them in multiples of your basic block size.&lt;br /&gt;
&lt;br /&gt;
You can check this quite easily.  Assuming a swidth/sunit of 1024/4096, and a block size of 4096, you should see a reported sunit/swidth of 128/512.  1024 * 512 == 128 * 4096.&lt;br /&gt;
&lt;br /&gt;
== Q: Why doesn&#039;t NFS-exporting subdirectories of inode64-mounted filesystem work? ==&lt;br /&gt;
&lt;br /&gt;
The default &amp;lt;tt&amp;gt;fsid&amp;lt;/tt&amp;gt; type encodes only 32-bit of the inode number for subdirectory exports.  However, exporting the root of the filesystem works, or using one of the non-default &amp;lt;tt&amp;gt;fsid&amp;lt;/tt&amp;gt; types (&amp;lt;tt&amp;gt;fsid=uuid&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;/etc/exports&amp;lt;/tt&amp;gt; with recent &amp;lt;tt&amp;gt;nfs-utils&amp;lt;/tt&amp;gt;) should work as well. (Thanks, Christoph!)&lt;br /&gt;
&lt;br /&gt;
== Q: What is the inode64 mount option for? ==&lt;br /&gt;
&lt;br /&gt;
By default, with 32bit inodes, XFS places inodes only in the first 1TB of a disk. If you have a disk with 100TB, all inodes will be stuck in the first TB. This can lead to strange things like &amp;quot;disk full&amp;quot; when you still have plenty space free, but there&#039;s no more place in the first TB to create a new inode. Also, performance sucks.&lt;br /&gt;
&lt;br /&gt;
To come around this, use the inode64 mount options for filesystems &amp;gt;1TB. Inodes will then be placed in the location where their data is, minimizing disk seeks.&lt;br /&gt;
&lt;br /&gt;
Beware that some old programs might have problems reading 64bit inodes, especially over NFS. Your editor used inode64 for over a year with recent (openSUSE 11.1 and higher) distributions using NFS and Samba without any corruptions, so that might be a recent enough distro.&lt;br /&gt;
&lt;br /&gt;
== Q: Can I just try the inode64 option to see if it helps me? ==&lt;br /&gt;
&lt;br /&gt;
Starting from kernel 2.6.35, you can try and then switch back. Older kernels have a bug leading to strange problems if you mount without inode64 again. For example, you can&#039;t access files &amp;amp; dirs that have been created with an inode &amp;gt;32bit anymore.&lt;br /&gt;
&lt;br /&gt;
== Q: Performance: mkfs.xfs -n size=64k option ==&lt;br /&gt;
&lt;br /&gt;
Asking the implications of that mkfs option on the XFS mailing list, Dave Chinner explained it this way:&lt;br /&gt;
&lt;br /&gt;
Inodes are not stored in the directory structure, only the directory entry name and the inode number. Hence the amount of space used by a&lt;br /&gt;
directory entry is determined by the length of the name.&lt;br /&gt;
&lt;br /&gt;
There is extra overhead to allocate large directory blocks (16 pages instead of one, to begin with, then there&#039;s the vmap overhead, etc), so for small directories smaller block sizes are faster for create and unlink operations.&lt;br /&gt;
&lt;br /&gt;
For empty directories, operations on 4k block sized directories consume roughly 50% less CPU that 64k block size directories. The 4k block size directories consume less CPU out to roughly 1.5 million entries where the two are roughly equal. At directory sizes of 10 million entries, 64k directory block operations are consuming about 15% of the CPU that 4k directory block operations consume.&lt;br /&gt;
&lt;br /&gt;
In terms of lookups, the 64k block directory will take less IO but consume more CPU for a given lookup. Hence it depends on your IO latency and whether directory readahead can hide that latency as to which will be faster. e.g. For SSDs, CPU usage might be the limiting factor, not the IO. Right now I don&#039;t have any numbers on what the difference might be - I&#039;m getting 1 billion inode population issues worked out first before I start on measuring cold cache lookup times on 1 billion files....&lt;br /&gt;
&lt;br /&gt;
== Q: I want to tune my XFS filesystems for &amp;lt;something&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
The standard answer you will get to this question is this: use the defaults.&lt;br /&gt;
&lt;br /&gt;
There are few workloads where using non-default mkfs.xfs or mount options make much sense. In general, the default values already used are optimised for best performance in the first place. mkfs.xfs will detect the difference between single disk and MD/DM RAID setups and change the default values it uses to  configure the filesystem appropriately.&lt;br /&gt;
&lt;br /&gt;
There are a lot of &amp;quot;XFS tuning guides&amp;quot; that Google will find for you - most are old, out of date and full of misleading or just plain incorrect information. Don&#039;t expect that tuning your filesystem for optimal bonnie++ numbers will mean your workload will go faster. You should only consider changing the defaults if either: a) you know from experience that your workload causes XFS a specific problem that can be worked around via a configuration change, or b) your workload is demonstrating bad performance when using the default configurations. In this case, you need to understand why your application is causing bad performance before you start tweaking XFS configurations.&lt;br /&gt;
&lt;br /&gt;
In most cases, the only thing you need to to consider for mkfs.xfs is specifying the stripe unit and width for hardware RAID devices. For mount options, the only thing that will change metadata performance considerably are the logbsize and delaylog mount options. Increasing logbsize reduces the number of journal IOs for a given workload, and delaylog will reduce them even further. The trade off for this increase in metadata performance is that more operations may be &amp;quot;missing&amp;quot; after recovery if the system crashes while actively making modifications.&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
	<entry>
		<id>https://xfs.org/index.php?title=XFS_FAQ&amp;diff=2123</id>
		<title>XFS FAQ</title>
		<link rel="alternate" type="text/html" href="https://xfs.org/index.php?title=XFS_FAQ&amp;diff=2123"/>
		<updated>2010-12-09T01:12:48Z</updated>

		<summary type="html">&lt;p&gt;Dgc: /* Q: Is using noatime or/and nodiratime at mount time giving any performance benefits in xfs (or not using them performance decrease)? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Info from: [http://oss.sgi.com/projects/xfs/faq.html main XFS faq at SGI]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Many thanks to earlier maintainers of this document - Thomas Graichen and Seth Mos.&lt;br /&gt;
&lt;br /&gt;
== Q: Where can I find documentation about XFS? ==&lt;br /&gt;
&lt;br /&gt;
The SGI XFS project page http://oss.sgi.com/projects/xfs/ is the definitive reference. It contains pointers to whitepapers, books, articles, etc.&lt;br /&gt;
&lt;br /&gt;
You could also join the [[XFS_email_list_and_archives|XFS mailing list]] or the &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;#xfs&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039; IRC channel on &#039;&#039;irc.freenode.net&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Q: Where can I find documentation about ACLs? ==&lt;br /&gt;
&lt;br /&gt;
Andreas Gruenbacher maintains the Extended Attribute and POSIX ACL documentation for Linux at http://acl.bestbits.at/&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;acl(5)&#039;&#039;&#039; manual page is also quite extensive.&lt;br /&gt;
&lt;br /&gt;
== Q: Where can I find information about the internals of XFS? ==&lt;br /&gt;
&lt;br /&gt;
An [http://oss.sgi.com/projects/xfs/training/ SGI XFS Training course] aimed at developers, triage and support staff, and serious users has been in development. Parts of the course are clearly still incomplete, but there is enough content to be useful to a broad range of users.&lt;br /&gt;
&lt;br /&gt;
Barry Naujok has documented the [http://oss.sgi.com/projects/xfs/papers/xfs_filesystem_structure.pdf XFS ondisk format] which is a very useful reference.&lt;br /&gt;
&lt;br /&gt;
== Q: What partition type should I use for XFS on Linux? ==&lt;br /&gt;
&lt;br /&gt;
Linux native filesystem (83).&lt;br /&gt;
&lt;br /&gt;
== Q: What mount options does XFS have? ==&lt;br /&gt;
&lt;br /&gt;
There are a number of mount options influencing XFS filesystems - refer to the &#039;&#039;&#039;mount(8)&#039;&#039;&#039; manual page or the documentation in the kernel source tree itself ([http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/filesystems/xfs.txt;hb=HEAD Documentation/filesystems/xfs.txt])&lt;br /&gt;
&lt;br /&gt;
== Q: Is there any relation between the XFS utilities and the kernel version? ==&lt;br /&gt;
&lt;br /&gt;
No, there is no relation. Newer utilities tend to mainly have fixes and checks the previous versions might not have. New features are also added in a backward compatible way - if they are enabled via mkfs, an incapable (old) kernel will recognize that it does not understand the new feature, and refuse to mount the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Q: Does it run on platforms other than i386? ==&lt;br /&gt;
&lt;br /&gt;
XFS runs on all of the platforms that Linux supports. It is more tested on the more common platforms, especially the i386 family. Its also well tested on the IA64 platform since thats the platform SGI Linux products use.&lt;br /&gt;
&lt;br /&gt;
== Q: Quota: Do quotas work on XFS? ==&lt;br /&gt;
&lt;br /&gt;
Yes.&lt;br /&gt;
&lt;br /&gt;
To use quotas with XFS, you need to enable XFS quota support when you configure your kernel. You also need to specify quota support when mounting. You can get the Linux quota utilities at their sourceforge website [http://sourceforge.net/projects/linuxquota/  http://sourceforge.net/projects/linuxquota/] or use &#039;&#039;&#039;xfs_quota(8)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Q: Quota: What&#039;s project quota? ==&lt;br /&gt;
&lt;br /&gt;
The  project  quota  is a quota mechanism in XFS can be used to implement a form of directory tree quota, where a specified directory and all of the files and subdirectories below it (i.e. a tree) can be restricted to using a subset of the available space in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Q: Quota: Can group quota and project quota be used at the same time? ==&lt;br /&gt;
&lt;br /&gt;
No, project quota cannot be used with group quota at the same time. On the other hand user quota and project quota can be used simultaneously.&lt;br /&gt;
&lt;br /&gt;
== Q: Quota: Is umounting prjquota (project quota) enabled fs and mounting it again with grpquota (group quota) removing prjquota limits previously set from fs (and vice versa) ? ==&lt;br /&gt;
&lt;br /&gt;
To be answered.&lt;br /&gt;
&lt;br /&gt;
== Q: Are there any dump/restore tools for XFS? ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;xfsdump(8)&#039;&#039;&#039; and &#039;&#039;&#039;xfsrestore(8)&#039;&#039;&#039; are fully supported. The tape format is the same as on IRIX, so tapes are interchangeable between operating systems.&lt;br /&gt;
&lt;br /&gt;
== Q: Does LILO work with XFS? ==&lt;br /&gt;
&lt;br /&gt;
This depends on where you install LILO.&lt;br /&gt;
&lt;br /&gt;
Yes, for MBR (Master Boot Record) installations.&lt;br /&gt;
&lt;br /&gt;
No, for root partition installations because the XFS superblock is written at block zero, where LILO would be installed. This is to maintain compatibility with the IRIX on-disk format, and will not be changed.&lt;br /&gt;
&lt;br /&gt;
== Q: Does GRUB work with XFS? ==&lt;br /&gt;
&lt;br /&gt;
There is native XFS filesystem support for GRUB starting with version 0.91 and onward. Unfortunately, GRUB used to make incorrect assumptions about being able to read a block device image while a filesystem is mounted and actively being written to, which could cause intermittent problems when using XFS. This has reportedly since been fixed, and the 0.97 version (at least) of GRUB is apparently stable.&lt;br /&gt;
&lt;br /&gt;
== Q: Can XFS be used for a root filesystem? ==&lt;br /&gt;
&lt;br /&gt;
Yes, with one caveat: Linux does not support an external XFS journal for the root filesystem via the &amp;quot;rootflags=&amp;quot; kernel parameter. To use an external journal for the root filesystem in Linux, an init ramdisk must mount the root filesystem with explicit &amp;quot;logdev=&amp;quot; specified. [http://mindplusplus.wordpress.com/2008/07/27/scratching-an-i.html More information here.]&lt;br /&gt;
&lt;br /&gt;
== Q: Will I be able to use my IRIX XFS filesystems on Linux? ==&lt;br /&gt;
&lt;br /&gt;
Yes. The on-disk format of XFS is the same on IRIX and Linux. Obviously, you should back-up your data before trying to move it between systems. Filesystems must be &amp;quot;clean&amp;quot; when moved (i.e. unmounted). If you plan to use IRIX filesystems on Linux keep the following points in mind: the kernel needs to have SGI partition support enabled; there is no XLV support in Linux, so you are unable to read IRIX filesystems which use the XLV volume manager; also not all blocksizes available on IRIX are available on Linux (only blocksizes less than or equal to the pagesize of the architecture: 4k for i386, ppc, ... 8k for alpha, sparc, ... is possible for now). Make sure that the directory format is version 2 on the IRIX filesystems (this is the default since IRIX 6.5.5). Linux can only read v2 directories.&lt;br /&gt;
&lt;br /&gt;
== Q: Is there a way to make a XFS filesystem larger or smaller? ==&lt;br /&gt;
&lt;br /&gt;
You can &#039;&#039;NOT&#039;&#039; make a XFS partition smaller online. The only way to shrink is to do a complete dump, mkfs and restore.&lt;br /&gt;
&lt;br /&gt;
An XFS filesystem may be enlarged by using &#039;&#039;&#039;xfs_growfs(8)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
If using partitions, you need to have free space after this partition to do so. Remove partition, recreate it larger with the &#039;&#039;exact same&#039;&#039; starting point. Run &#039;&#039;&#039;xfs_growfs&#039;&#039;&#039; to make the partition larger. Note - editing partition tables is a dangerous pastime, so back up your filesystem before doing so.&lt;br /&gt;
&lt;br /&gt;
Using XFS filesystems on top of a volume manager makes this a lot easier.&lt;br /&gt;
&lt;br /&gt;
== Q: What information should I include when reporting a problem? ==&lt;br /&gt;
&lt;br /&gt;
Things to include are what version of XFS you are using, if this is a CVS version of what date and version of the kernel. If you have problems with userland packages please report the version of the package you are using.&lt;br /&gt;
&lt;br /&gt;
If the problem relates to a particular filesystem, the output from the &#039;&#039;&#039;xfs_info(8)&#039;&#039;&#039; command and any &#039;&#039;&#039;mount(8)&#039;&#039;&#039; options in use will also be useful to the developers.&lt;br /&gt;
&lt;br /&gt;
If you experience an oops, please run it through &#039;&#039;&#039;ksymoops&#039;&#039;&#039; so that it can be interpreted.&lt;br /&gt;
&lt;br /&gt;
If you have a filesystem that cannot be repaired, make sure you have xfsprogs 2.9.0 or later and run &#039;&#039;&#039;xfs_metadump(8)&#039;&#039;&#039; to capture the metadata (which obfuscates filenames and attributes to protect your privacy) and make the dump available for someone to analyse.&lt;br /&gt;
&lt;br /&gt;
== Q: Mounting an XFS filesystem does not work - what is wrong? ==&lt;br /&gt;
&lt;br /&gt;
If mount prints an error message something like:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
     mount: /dev/hda5 has wrong major or minor number&lt;br /&gt;
&lt;br /&gt;
you either do not have XFS compiled into the kernel (or you forgot to load the modules) or you did not use the &amp;quot;-t xfs&amp;quot; option on mount or the &amp;quot;xfs&amp;quot; option in &amp;lt;tt&amp;gt;/etc/fstab&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If you get something like:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 mount: wrong fs type, bad option, bad superblock on /dev/sda1,&lt;br /&gt;
        or too many mounted file systems&lt;br /&gt;
&lt;br /&gt;
Refer to your system log file (&amp;lt;tt&amp;gt;/var/log/messages&amp;lt;/tt&amp;gt;) for a detailed diagnostic message from the kernel.&lt;br /&gt;
&lt;br /&gt;
== Q: Does the filesystem have an undelete capability? ==&lt;br /&gt;
&lt;br /&gt;
There is no undelete in XFS. However at least some XFS driver implementations does not wipe file information nodes completely so there are chance to recover files with specialized commercial software like [http://www.ufsexplorer.com/rdr_xfs.php Raise Data Recovery for XFS].&lt;br /&gt;
In this kind of XFS driver implementation it does not re-use directory entries immediately so there are chance to get back recently deleted files even with their real names.&lt;br /&gt;
&lt;br /&gt;
This applies to most recent Linux distributions, as well as to most popular NAS boxes that use embedded linux and XFS file system.&lt;br /&gt;
&lt;br /&gt;
Anyway, the best is to always keep backups.&lt;br /&gt;
&lt;br /&gt;
== Q: How can I backup a XFS filesystem and ACLs? ==&lt;br /&gt;
&lt;br /&gt;
You can backup a XFS filesystem with utilities like &#039;&#039;&#039;xfsdump(8)&#039;&#039;&#039; and standard &#039;&#039;&#039;tar(1)&#039;&#039;&#039; for standard files. If you want to backup ACLs you will need to use &#039;&#039;&#039;xfsdump&#039;&#039;&#039; or [http://www.bacula.org/en/dev-manual/Current_State_Bacula.html Bacula] (&amp;gt; version 3.1.4) or [http://rsync.samba.org/ rsync] (&amp;gt;= version 3.0.0) to backup ACLs and EAs. &#039;&#039;&#039;xfsdump&#039;&#039;&#039; can also be integrated with [http://www.amanda.org/ amanda(8)].&lt;br /&gt;
&lt;br /&gt;
== Q: I see applications returning error 990 or &amp;quot;Structure needs cleaning&amp;quot;, what is wrong? ==&lt;br /&gt;
&lt;br /&gt;
The error 990 stands for [http://oss.sgi.com/cgi-bin/gitweb.cgi?p=xfs/xfs.git;a=blob;f=fs/xfs/linux-2.6/xfs_linux.h#l145 EFSCORRUPTED] which usually means XFS has detected a filesystem metadata problem and has shut the filesystem down to prevent further damage. Also, since about June 2006, we [http://oss.sgi.com/cgi-bin/gitweb.cgi?p=xfs/xfs.git;a=commit;h=da2f4d679c8070ba5b6a920281e495917b293aa0 converted from EFSCORRUPTED/990 over to using EUCLEAN], &amp;quot;Structure needs cleaning.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The cause can be pretty much anything, unfortunately - filesystem, virtual memory manager, volume manager, device driver, or hardware.&lt;br /&gt;
&lt;br /&gt;
There should be a detailed console message when this initially happens. The messages have important information giving hints to developers as to the earliest point that a problem was detected. It is there to protect your data.&lt;br /&gt;
&lt;br /&gt;
You can use xfs_check and xfs_repair to remedy the problem (with the file system unmounted).&lt;br /&gt;
&lt;br /&gt;
== Q: Why do I see binary NULLS in some files after recovery when I unplugged the power? ==&lt;br /&gt;
&lt;br /&gt;
Update: This issue has been addressed with a CVS fix on the 29th March 2007 and merged into mainline on 8th May 2007 for 2.6.22-rc1.&lt;br /&gt;
&lt;br /&gt;
XFS journals metadata updates, not data updates. After a crash you are supposed to get a consistent filesystem which looks like the state sometime shortly before the crash, NOT what the in memory image looked like the instant before the crash.&lt;br /&gt;
&lt;br /&gt;
Since XFS does not write data out immediately unless you tell it to with fsync, an O_SYNC or O_DIRECT open (the same is true of other filesystems), you are looking at an inode which was flushed out, but whose data was not. Typically you&#039;ll find that the inode is not taking any space since all it has is a size but no extents allocated (try examining the file with the &#039;&#039;&#039;xfs_bmap(8)&#039;&#039;&#039; command).&lt;br /&gt;
&lt;br /&gt;
== Q: What is the problem with the write cache on journaled filesystems? ==&lt;br /&gt;
&lt;br /&gt;
Many drives use a write back cache in order to speed up the performance of writes.  However, there are conditions such as power failure when the write cache memory is never flushed to the actual disk.  Further, the drive can de-stage data from the write cache to the platters in any order that it chooses.  This causes problems for XFS and journaled filesystems in general because they rely on knowing when a write has completed to the disk. They need to know that the log information has made it to disk before allowing metadata to go to disk.  When the metadata makes it to disk then the transaction can effectively be deleted from the log resulting in movement of the tail of the log and thus freeing up some log space. So if the writes never make it to the physical disk, then the ordering is violated and the log and metadata can be lost, resulting in filesystem corruption.&lt;br /&gt;
&lt;br /&gt;
With hard disk cache sizes of currently (Jan 2009) up to 32MB that can be a lot of valuable information.  In a RAID with 8 such disks these adds to 256MB, and the chance of having filesystem metadata in the cache is so high that you have a very high chance of big data losses on a power outage.&lt;br /&gt;
&lt;br /&gt;
With a single hard disk and barriers turned on (on=default), the drive write cache is flushed before and after a barrier is issued.  A powerfail &amp;quot;only&amp;quot; loses data in the cache but no essential ordering is violated, and corruption will not occur.&lt;br /&gt;
&lt;br /&gt;
With a RAID controller with battery backed controller cache and cache in write back mode, you should turn off barriers - they are unnecessary in this case, and if the controller honors the cache flushes, it will be harmful to performance.  But then you *must* disable the individual hard disk write cache in order to ensure to keep the filesystem intact after a power failure. The method for doing this is different for each RAID controller. See the section about RAID controllers below.&lt;br /&gt;
&lt;br /&gt;
== Q: How can I tell if I have the disk write cache enabled? ==&lt;br /&gt;
&lt;br /&gt;
For SCSI/SATA:&lt;br /&gt;
&lt;br /&gt;
* Look in dmesg(8) output for a driver line, such as:&amp;lt;br /&amp;gt; &amp;quot;SCSI device sda: drive cache: write back&amp;quot;&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;# sginfo -c /dev/sda | grep -i &#039;write cache&#039; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For PATA/SATA (although for SATA this only works on a recent kernel with ATA command passthrough):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;# hdparm -I /dev/sda&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; and look under &amp;quot;Enabled Supported&amp;quot; for &amp;quot;Write cache&amp;quot;&lt;br /&gt;
&lt;br /&gt;
For RAID controllers:&lt;br /&gt;
&lt;br /&gt;
* See the section about RAID controllers below&lt;br /&gt;
&lt;br /&gt;
== Q: How can I address the problem with the disk write cache? ==&lt;br /&gt;
&lt;br /&gt;
=== Disabling the disk write back cache. ===&lt;br /&gt;
&lt;br /&gt;
For SATA/PATA(IDE): (although for SATA this only works on a recent kernel with ATA command passthrough):&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;# hdparm -W0 /dev/sda&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; # hdparm -W0 /dev/hda&lt;br /&gt;
* &amp;lt;nowiki&amp;gt;# blktool /dev/sda wcache off&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; # blktool /dev/hda wcache off&lt;br /&gt;
&lt;br /&gt;
For SCSI:&lt;br /&gt;
&lt;br /&gt;
* Using sginfo(8) which is a little tedious&amp;lt;br /&amp;gt; It takes 3 steps. For example:&lt;br /&gt;
*# &amp;lt;nowiki&amp;gt;#sginfo -c /dev/sda&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; which gives a list of attribute names and values&lt;br /&gt;
*# &amp;lt;nowiki&amp;gt;#sginfo -cX /dev/sda&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; which gives an array of cache values which you must match up with from step 1, e.g.&amp;lt;br /&amp;gt; 0 0 0 1 0 1 0 0 0 0 65535 0 65535 65535 1 0 0 0 3 0 0&lt;br /&gt;
*# &amp;lt;nowiki&amp;gt;#sginfo -cXR /dev/sda 0 0 0 1 0 0 0 0 0 0 65535 0 65535 65535 1 0 0 0 3 0 0&amp;lt;/nowiki&amp;gt;&amp;lt;br /&amp;gt; allows you to reset the value of the cache attributes.&lt;br /&gt;
&lt;br /&gt;
For RAID controllers:&lt;br /&gt;
&lt;br /&gt;
* See the section about RAID controllers below&lt;br /&gt;
&lt;br /&gt;
This disabling is kept persistent for a SCSI disk. However, for a SATA/PATA disk this needs to be done after every reset as it will reset back to the default of the write cache enabled. And a reset can happen after reboot or on error recovery of the drive. This makes it rather difficult to guarantee that the write cache is maintained as disabled.&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using an external log. ===&lt;br /&gt;
&lt;br /&gt;
Some people have considered the idea of using an external log on a separate drive with the write cache disabled and the rest of the file system on another disk with the write cache enabled. However, that will &#039;&#039;&#039;not&#039;&#039;&#039; solve the problem. For example, the tail of the log is moved when we are notified that a metadata write is completed to disk and we won&#039;t be able to guarantee that if the metadata is on a drive with the write cache enabled.&lt;br /&gt;
&lt;br /&gt;
In fact using an external log will disable XFS&#039; write barrier support.&lt;br /&gt;
&lt;br /&gt;
=== Write barrier support. ===&lt;br /&gt;
&lt;br /&gt;
Write barrier support is enabled by default in XFS since kernel version 2.6.17. It is disabled by mounting the filesystem with &amp;quot;nobarrier&amp;quot;. Barrier support will flush the write back cache at the appropriate times (such as on XFS log writes). This is generally the recommended solution, however, you should check the system logs to ensure it was successful. Barriers will be disabled and reported in the log if any of the 3 scenarios occurs:&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;Disabling barriers, not supported with external log device&amp;quot;&lt;br /&gt;
* &amp;quot;Disabling barriers, not supported by the underlying device&amp;quot;&lt;br /&gt;
* &amp;quot;Disabling barriers, trial barrier write failed&amp;quot;&lt;br /&gt;
&lt;br /&gt;
If the filesystem is mounted with an external log device then we currently don&#039;t support flushing to the data and log devices (this may change in the future). If the driver tells the block layer that the device does not support write cache flushing with the write cache enabled then it will report that the device doesn&#039;t support it. And finally we will actually test out a barrier write on the superblock and test its error state afterwards, reporting if it fails.&lt;br /&gt;
&lt;br /&gt;
== Q. Should barriers be enabled with storage which has a persistent write cache? ==&lt;br /&gt;
&lt;br /&gt;
Many hardware RAID have a persistent write cache which preserves it across power failure, interface resets, system crashes, etc. Using write barriers in this instance is not recommended and will in fact lower performance. Therefore, it is recommended to turn off the barrier support and mount the filesystem with &amp;quot;nobarrier&amp;quot;. But take care about the hard disk write cache, which should be off.&lt;br /&gt;
&lt;br /&gt;
== Q. Which settings does my RAID controller need ? ==&lt;br /&gt;
&lt;br /&gt;
It&#039;s hard to tell because there are so many controllers. Please consult your RAID controller documentation to determine how to change these settings, but we try to give an overview here:&lt;br /&gt;
&lt;br /&gt;
Real RAID controllers (not those found onboard of mainboards) normally have a battery backed cache (or an [http://en.wikipedia.org/wiki/Electric_double-layer_capacitor ultracapacitor] + flash memory &amp;quot;[http://www.tweaktown.com/articles/2800/adaptec_zero_maintenance_cache_protection_explained/ zero maintenance cache]&amp;quot;) which is used for buffering writes to improve speed. Even if it&#039;s battery backed, the individual hard disk write caches need to be turned off, as they are not protected from a powerfail and will just lose all contents in that case.&lt;br /&gt;
&lt;br /&gt;
* onboard RAID controllers: there are so many different types it&#039;s hard to tell. Generally, those controllers have no cache, but let the hard disk write cache on. That can lead to the bad situation that after a powerfail with RAID-1 when only parts of the disk cache have been written, the controller doesn&#039;t even see that the disks are out of sync, as the disks can resort cached blocks and might have saved the superblock info, but then lost different data contents. So, turn off disk write caches before using the RAID function.&lt;br /&gt;
&lt;br /&gt;
* 3ware: /cX/uX set cache=off, see http://www.3ware.com/support/UserDocs/CLIGuide-9.5.1.1.pdf , page 86&lt;br /&gt;
&lt;br /&gt;
* Adaptec: allows setting individual drives cache&lt;br /&gt;
arcconf setcache &amp;lt;disk&amp;gt; wb|wt&lt;br /&gt;
wb=write back, which means write cache on, wt=write through, which means write cache off. So &amp;quot;wt&amp;quot; should be chosen.&lt;br /&gt;
&lt;br /&gt;
* Areca: In archttp under &amp;quot;System Controls&amp;quot; -&amp;gt; &amp;quot;System Configuration&amp;quot; there&#039;s the option &amp;quot;Disk Write Cache Mode&amp;quot; (defaults &amp;quot;Auto&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Off&amp;quot;: disk write cache is turned off&lt;br /&gt;
&lt;br /&gt;
&amp;quot;On&amp;quot;: disk write cache is enabled, this is not save for your data but fast&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Auto&amp;quot;: If you use a BBM (battery backup module, which you really should use if you care about your data), the controller automatically turns disk writes off, to protect your data. In case no BBM is attached, the controller switches to &amp;quot;On&amp;quot;, because neither controller cache nor disk cache is save so you don&#039;t seem to care about your data and just want high speed (which you get then).&lt;br /&gt;
&lt;br /&gt;
That&#039;s a very sensible default so you can let it &amp;quot;Auto&amp;quot; or enforce &amp;quot;Off&amp;quot; to be sure.&lt;br /&gt;
&lt;br /&gt;
* LSI MegaRAID: allows setting individual disks cache:&lt;br /&gt;
MegaCli -AdpCacheFlush -aN|-a0,1,2|-aALL -EnDskCache|DisDskCache&lt;br /&gt;
&lt;br /&gt;
* Xyratex: from the docs: &amp;quot;Write cache includes the disk drive cache and controller cache.&amp;quot;. So that means you can only set the drive caches and the unit caches together. To protect your data, turn it off, but write performance will suffer badly as also the controller write cache is disabled.&lt;br /&gt;
&lt;br /&gt;
== Q: Which settings are best with virtualization like VMware, XEN, qemu? ==&lt;br /&gt;
&lt;br /&gt;
The biggest problem is that those products seem to also virtualize disk &lt;br /&gt;
writes in a way that even barriers don&#039;t work anymore, which means even &lt;br /&gt;
a fsync is not reliable. Tests confirm that unplugging the power from &lt;br /&gt;
such a system even with RAID controller with battery backed cache and &lt;br /&gt;
hard disk cache turned off (which is save on a normal host) you can &lt;br /&gt;
destroy a database within the virtual machine (client, domU whatever you &lt;br /&gt;
call it).&lt;br /&gt;
&lt;br /&gt;
In qemu you can specify cache=off on the line specifying the virtual &lt;br /&gt;
disk. For others information is missing.&lt;br /&gt;
&lt;br /&gt;
== Q: What is the issue with directory corruption in Linux 2.6.17? ==&lt;br /&gt;
&lt;br /&gt;
In the Linux kernel 2.6.17 release a subtle bug was accidentally introduced into the XFS directory code by some &amp;quot;sparse&amp;quot; endian annotations. This bug was sufficiently uncommon (it only affects a certain type of format change, in Node or B-Tree format directories, and only in certain situations) that it was not detected during our regular regression testing, but it has been observed in the wild by a number of people now.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Update: the fix is included in 2.6.17.7 and later kernels.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
To add insult to injury, &#039;&#039;&#039;xfs_repair(8)&#039;&#039;&#039; is currently not correcting these directories on detection of this corrupt state either. This &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; issue is actively being worked on, and a fixed version will be available shortly.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Update: a fixed &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; is now available; version 2.8.10 or later of the xfsprogs package contains the fixed version.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
No other kernel versions are affected. However, using a corrupt filesystem on other kernels can still result in the filesystem being shutdown if the problem has not been rectified (on disk), making it seem like other kernels are affected.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;xfs_check&#039;&#039;&#039; tool, or &#039;&#039;&#039;xfs_repair -n&#039;&#039;&#039;, should be able to detect any directory corruption.&lt;br /&gt;
&lt;br /&gt;
Until a fixed &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; binary is available, one can make use of the &#039;&#039;&#039;xfs_db(8)&#039;&#039;&#039; command to mark the problem directory for removal (see the example below). A subsequent &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; invocation will remove the directory and move all contents into &amp;quot;lost+found&amp;quot;, named by inode number (see second example on how to map inode number to directory entry name, which needs to be done _before_ removing the directory itself). The inode number of the corrupt directory is included in the shutdown report issued by the kernel on detection of directory corruption. Using that inode number, this is how one would ensure it is removed:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 # xfs_db -x /dev/sdXXX&lt;br /&gt;
 xfs_db&amp;amp;gt; inode NNN&lt;br /&gt;
 xfs_db&amp;amp;gt; print&lt;br /&gt;
 core.magic = 0x494e&lt;br /&gt;
 core.mode = 040755&lt;br /&gt;
 core.version = 2&lt;br /&gt;
 core.format = 3 (btree)&lt;br /&gt;
 ...&lt;br /&gt;
 xfs_db&amp;amp;gt; write core.mode 0&lt;br /&gt;
 xfs_db&amp;amp;gt; quit&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A subsequent &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; will clear the directory, and add new entries (named by inode number) in lost+found.&lt;br /&gt;
&lt;br /&gt;
The easiest way to map inode numbers to full paths is via &#039;&#039;&#039;xfs_ncheck(8)&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;: &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 # xfs_ncheck -i 14101 -i 14102 /dev/sdXXX&lt;br /&gt;
       14101 full/path/mumble_fratz_foo_bar_1495&lt;br /&gt;
       14102 full/path/mumble_fratz_foo_bar_1494&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Should this not work, we can manually map inode numbers in B-Tree format directory by taking the following steps:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
 # xfs_db -x /dev/sdXXX&lt;br /&gt;
 xfs_db&amp;amp;gt; inode NNN&lt;br /&gt;
 xfs_db&amp;amp;gt; print&lt;br /&gt;
 core.magic = 0x494e&lt;br /&gt;
 ...&lt;br /&gt;
 next_unlinked = null&lt;br /&gt;
 u.bmbt.level = 1&lt;br /&gt;
 u.bmbt.numrecs = 1&lt;br /&gt;
 u.bmbt.keys[1] = [startoff] 1:[0]&lt;br /&gt;
 u.bmbt.ptrs[1] = 1:3628&lt;br /&gt;
 xfs_db&amp;amp;gt; fsblock 3628&lt;br /&gt;
 xfs_db&amp;amp;gt; type bmapbtd&lt;br /&gt;
 xfs_db&amp;amp;gt; print&lt;br /&gt;
 magic = 0x424d4150&lt;br /&gt;
 level = 0&lt;br /&gt;
 numrecs = 19&lt;br /&gt;
 leftsib = null&lt;br /&gt;
 rightsib = null&lt;br /&gt;
 recs[1-19] = [startoff,startblock,blockcount,extentflag]&lt;br /&gt;
        1:[0,3088,4,0] 2:[4,3128,8,0] 3:[12,3308,4,0] 4:[16,3360,4,0]&lt;br /&gt;
        5:[20,3496,8,0] 6:[28,3552,8,0] 7:[36,3624,4,0] 8:[40,3633,4,0]&lt;br /&gt;
        9:[44,3688,8,0] 10:[52,3744,4,0] 11:[56,3784,8,0]&lt;br /&gt;
        12:[64,3840,8,0] 13:[72,3896,4,0] 14:[33554432,3092,4,0]&lt;br /&gt;
        15:[33554436,3488,8,0] 16:[33554444,3629,4,0]&lt;br /&gt;
        17:[33554448,3748,4,0] 18:[33554452,3900,4,0]&lt;br /&gt;
        19:[67108864,3364,4,0]&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At this point we are looking at the extents that hold all of the directory information. There are three types of extent here, we have the data blocks (extents 1 through 13 above), then the leaf blocks (extents 14 through 18), then the freelist blocks (extent 19 above). The jumps in the first field (start offset) indicate our progression through each of the three types. For recovering file names, we are only interested in the data blocks, so we can now feed those offset numbers into the &#039;&#039;&#039;xfs_db&#039;&#039;&#039; dblock command. So, for the fifth extent - 5:[20,3496,8,0] - listed above:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 ...&lt;br /&gt;
 xfs_db&amp;amp;gt; dblock 20&lt;br /&gt;
 xfs_db&amp;amp;gt; print&lt;br /&gt;
 dhdr.magic = 0x58443244&lt;br /&gt;
 dhdr.bestfree[0].offset = 0&lt;br /&gt;
 dhdr.bestfree[0].length = 0&lt;br /&gt;
 dhdr.bestfree[1].offset = 0&lt;br /&gt;
 dhdr.bestfree[1].length = 0&lt;br /&gt;
 dhdr.bestfree[2].offset = 0&lt;br /&gt;
 dhdr.bestfree[2].length = 0&lt;br /&gt;
 du[0].inumber = 13937&lt;br /&gt;
 du[0].namelen = 25&lt;br /&gt;
 du[0].name = &amp;quot;mumble_fratz_foo_bar_1595&amp;quot;&lt;br /&gt;
 du[0].tag = 0x10&lt;br /&gt;
 du[1].inumber = 13938&lt;br /&gt;
 du[1].namelen = 25&lt;br /&gt;
 du[1].name = &amp;quot;mumble_fratz_foo_bar_1594&amp;quot;&lt;br /&gt;
 du[1].tag = 0x38&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
So, here we can see that inode number 13938 matches up with name &amp;quot;mumble_fratz_foo_bar_1594&amp;quot;. Iterate through all the extents, and extract all the name-to-inode-number mappings you can, as these will be useful when looking at &amp;quot;lost+found&amp;quot; (once &#039;&#039;&#039;xfs_repair&#039;&#039;&#039; has removed the corrupt directory).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Q: Why does my &amp;gt; 2TB XFS partition disappear when I reboot ? ==&lt;br /&gt;
&lt;br /&gt;
Strictly speaking this is not an XFS problem.&lt;br /&gt;
&lt;br /&gt;
To support &amp;gt; 2TB partitions you need two things: a kernel that supports large block devices (&amp;lt;tt&amp;gt;CONFIG_LBD=y&amp;lt;/tt&amp;gt;) and a partition table format that can hold large partitions.  The default DOS partition tables don&#039;t.  The best partition format for&lt;br /&gt;
&amp;gt; 2TB partitions is the EFI GPT format (&amp;lt;tt&amp;gt;CONFIG_EFI_PARTITION=y&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Without CONFIG_LBD=y you can&#039;t even create the filesystem, but without &amp;lt;tt&amp;gt;CONFIG_EFI_PARTITION=y&amp;lt;/tt&amp;gt; it works fine until you reboot at which point the partition will disappear.  Note that you need to enable the &amp;lt;tt&amp;gt;CONFIG_PARTITION_ADVANCED&amp;lt;/tt&amp;gt; option before you can set &amp;lt;tt&amp;gt;CONFIG_EFI_PARTITION=y&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Q: Why do I receive &amp;lt;tt&amp;gt;No space left on device&amp;lt;/tt&amp;gt; after &amp;lt;tt&amp;gt;xfs_growfs&amp;lt;/tt&amp;gt;? ==&lt;br /&gt;
&lt;br /&gt;
After [http://oss.sgi.com/pipermail/xfs/2009-January/039828.html growing a XFS filesystem], df(1) would show enough free space but attempts to write to the filesystem result in -ENOSPC. To fix this, [http://oss.sgi.com/pipermail/xfs/2009-January/039835.html Dave Chinner advised]:&lt;br /&gt;
&lt;br /&gt;
  The only way to fix this is to move data around to free up space&lt;br /&gt;
  below 1TB. Find your oldest data (i.e. that was around before even&lt;br /&gt;
  the first grow) and move it off the filesystem (move, not copy).&lt;br /&gt;
  Then if you copy it back on, the data blocks will end up above 1TB&lt;br /&gt;
  and that should leave you with plenty of space for inodes below 1TB.&lt;br /&gt;
  &lt;br /&gt;
  A complete dump and restore will also fix the problem ;)&lt;br /&gt;
&lt;br /&gt;
Also, you can add &#039;inode64&#039; to your mount options to allow inodes to live above 1TB.&lt;br /&gt;
&lt;br /&gt;
== Q: Is using noatime or/and nodiratime at mount time giving any performance benefits in xfs (or not using them performance decrease)? ==&lt;br /&gt;
&lt;br /&gt;
The default atime behaviour is relatime, which has almost no overhead compared to noatime but still maintains sane atime values. All Linux filesystems use this as the default now (since around 2.6.30), but XFS has used relatime-like behaviour since 2006, so no-one should really need to ever use noatime on XFS for performance reasons. &lt;br /&gt;
&lt;br /&gt;
Also, noatime implies nodiratime, so there is never a need to specify nodiratime when noatime is also specified.&lt;br /&gt;
&lt;br /&gt;
== Q: How to get around a bad inode repair is unable to clean up ==&lt;br /&gt;
&lt;br /&gt;
The trick is go in with xfs_db and mark the inode as a deleted, which will cause repair to clean it up and finish the remove process.&lt;br /&gt;
&lt;br /&gt;
  xfs_db -x -c &#039;inode XXX&#039; -c &#039;write core.nextents 0&#039; -c &#039;write core.size 0&#039; /dev/hdXX&lt;br /&gt;
&lt;br /&gt;
== Q: How to calculate the correct sunit,swidth values for optimal performance ==&lt;br /&gt;
&lt;br /&gt;
XFS allows to optimize for a given RAID stripe size and number of disks via mount options. The calculation of these values is quite simple:&lt;br /&gt;
&lt;br /&gt;
  su = &amp;lt;RAID controllers stripe size in BYTES (or KiBytes when used with k)&amp;gt;&lt;br /&gt;
  sw = &amp;lt;# of data disks&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So if your RAID controller has a stripe size of 64KB, and you have a RAID-6 with 8 disks, use&lt;br /&gt;
&lt;br /&gt;
  su = 64k&lt;br /&gt;
  sw = 6 (RAID-6 of 8 disks has 6 data disks)&lt;br /&gt;
&lt;br /&gt;
A RAID stripe size of 256KB with a RAID-10 over 16 disks should use&lt;br /&gt;
&lt;br /&gt;
  su = 256k&lt;br /&gt;
  sw = 8 (RAID-10 of 16 disks has 8 data disks)&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can use &amp;quot;sunit&amp;quot; instead of &amp;quot;su&amp;quot;, but then the value means &amp;quot;number of 512B sectors&amp;quot;, and you *must* use &amp;quot;swidth&amp;quot; then as &amp;quot;number of 512B sectors&amp;quot; then as well!&lt;br /&gt;
&lt;br /&gt;
Please be aware that when xfs_info or mkfs.xfs report the sunit/swidth values, they use a different unit size than above.  Whereas sunit and swidth are first specified in 512B sectors, xfs_info and mkfs.xfs report them in multiples of your basic block size.&lt;br /&gt;
&lt;br /&gt;
You can check this quite easily.  Assuming a swidth/sunit of 1024/4096, and a block size of 4096, you should see a reported sunit/swidth of 128/512.  1024 * 512 == 128 * 4096.&lt;br /&gt;
&lt;br /&gt;
== Q: Why doesn&#039;t NFS-exporting subdirectories of inode64-mounted filesystem work? ==&lt;br /&gt;
&lt;br /&gt;
The default &amp;lt;tt&amp;gt;fsid&amp;lt;/tt&amp;gt; type encodes only 32-bit of the inode number for subdirectory exports.  However, exporting the root of the filesystem works, or using one of the non-default &amp;lt;tt&amp;gt;fsid&amp;lt;/tt&amp;gt; types (&amp;lt;tt&amp;gt;fsid=uuid&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;/etc/exports&amp;lt;/tt&amp;gt; with recent &amp;lt;tt&amp;gt;nfs-utils&amp;lt;/tt&amp;gt;) should work as well. (Thanks, Christoph!)&lt;br /&gt;
&lt;br /&gt;
== Q: What is the inode64 mount option for? ==&lt;br /&gt;
&lt;br /&gt;
By default, with 32bit inodes, XFS places inodes only in the first 1TB of a disk. If you have a disk with 100TB, all inodes will be stuck in the first TB. This can lead to strange things like &amp;quot;disk full&amp;quot; when you still have plenty space free, but there&#039;s no more place in the first TB to create a new inode. Also, performance sucks.&lt;br /&gt;
&lt;br /&gt;
To come around this, use the inode64 mount options for filesystems &amp;gt;1TB. Inodes will then be placed in the location where their data is, minimizing disk seeks.&lt;br /&gt;
&lt;br /&gt;
Beware that some old programs might have problems reading 64bit inodes, especially over NFS. Your editor used inode64 for over a year with recent (openSUSE 11.1 and higher) distributions using NFS and Samba without any corruptions, so that might be a recent enough distro.&lt;br /&gt;
&lt;br /&gt;
== Q: Can I just try the inode64 option to see if it helps me? ==&lt;br /&gt;
&lt;br /&gt;
Starting from kernel 2.6.35, you can try and then switch back. Older kernels have a bug leading to strange problems if you mount without inode64 again. For example, you can&#039;t access files &amp;amp; dirs that have been created with an inode &amp;gt;32bit anymore.&lt;br /&gt;
&lt;br /&gt;
== Q: Performance: mkfs.xfs -n size=64k option ==&lt;br /&gt;
&lt;br /&gt;
Asking the implications of that mkfs option on the XFS mailing list, Dave Chinner explained it this way:&lt;br /&gt;
&lt;br /&gt;
Inodes are not stored in the directory structure, only the directory entry name and the inode number. Hence the amount of space used by a&lt;br /&gt;
directory entry is determined by the length of the name.&lt;br /&gt;
&lt;br /&gt;
There is extra overhead to allocate large directory blocks (16 pages instead of one, to begin with, then there&#039;s the vmap overhead, etc), so for small directories smaller block sizes are faster for create and unlink operations.&lt;br /&gt;
&lt;br /&gt;
For empty directories, operations on 4k block sized directories consume roughly 50% less CPU that 64k block size directories. The 4k block size directories consume less CPU out to roughly 1.5 million entries where the two are roughly equal. At directory sizes of 10 million entries, 64k directory block operations are consuming about 15% of the CPU that 4k directory block operations consume.&lt;br /&gt;
&lt;br /&gt;
In terms of lookups, the 64k block directory will take less IO but consume more CPU for a given lookup. Hence it depends on your IO latency and whether directory readahead can hide that latency as to which will be faster. e.g. For SSDs, CPU usage might be the limiting factor, not the IO. Right now I don&#039;t have any numbers on what the difference might be - I&#039;m getting 1 billion inode population issues worked out first before I start on measuring cold cache lookup times on 1 billion files....&lt;/div&gt;</summary>
		<author><name>Dgc</name></author>
	</entry>
</feed>