It seems like about once a year I have to see threads like the recent one on the Xsan Mailing List from Apple (yes, that one hasn’t been deprecated juuuust yet). This type of thread is really just FUD. People say “Xsan is going away” or “Apple doesn’t care about us” or something like that. But, in order to be compatible with some of the later versions of StorNext, Xsan is in the process of an underlying update that most likely haven’t noticed. The first thing is that all of the binaries of gone back into /System/Library/Filesystems, now located in /System/Library/Filesystems/acfs.fs/Contents/bin (or if not, symlinked). The second is that we have a few new commands in our toolbelt, aptly named with a prefix of sncfg, including sncfgconvert, sncfgedit, sncfginstall, sncfgquery, sncfgremove, sncfgtemplate and sncfgvalidate.
There aren’t any man pages for these commands and help/usage information is sparse at best. However, the names are pretty straight forward in telling a compelling story about what they do and there is a man page for snfs.cfgx, the new format of files. As the name of the files would imply, the new format has a cfgx file extension. You can read all about the structure and the way that you build and manage arrays and namespaces when you have time to read the man page. In the meantime, let’s look at the sncfgtemplate command first. This command can create a template of a volume configuration file based on the existing contents of a volume configuration file. Let’s run sncfgtemplate with an option for -n and specify an active volume name:
/System/Library/Filesystems/acfs.fs/Contents/bin/sncfgtemplate -n MYVOLUME
This is going to output a n XML structure that can be used, for example, to use your volume in StorNext or possibly to run your volume with the later StorNext style of config file. This also involves exposing more options to users, such as keys for haFsType, as can be seen in the below configuration file structure:
<?xml version="1.0"?>
<configDoc xmlns="http://www.quantum.com/snfs" version="1.0">
<config configVersion="0" name="MYVOLUME" fsBlockSize="16384" journalSize="16777216">
<globals>
<abmFreeLimit>false</abmFreeLimit>
<allocationStrategy>round</allocationStrategy>
<haFsType>HaUnmonitored</haFsType>
<bufferCacheSize>33554432</bufferCacheSize>
<cvRootDir>/</cvRootDir>
<storageManager>false</storageManager>
<dataMigrationThreadPoolSize>128</dataMigrationThreadPoolSize>
<debug>00000000</debug>
<dirWarp>true</dirWarp>
<extentCountThreshold>49152</extentCountThreshold>
<enableSpotlight>false</enableSpotlight>
<enforceAcls>false</enforceAcls>
<fileLocks>false</fileLocks>
<fileLockResyncTimeOut>20</fileLockResyncTimeOut>
<forcePerfectFit>false</forcePerfectFit>
<fsCapacityThreshold>0</fsCapacityThreshold>
<globalSuperUser>true</globalSuperUser>
<inodeCacheSize>32768</inodeCacheSize>
<inodeExpandMin>0</inodeExpandMin>
<inodeExpandInc>0</inodeExpandInc>
<inodeExpandMax>0</inodeExpandMax>
<inodeDeleteMax>0</inodeDeleteMax>
<inodeStripeWidth>0</inodeStripeWidth>
<maxConnections>32</maxConnections>
<maxLogs>4</maxLogs>
<namedStreams>false</namedStreams>
<remoteNotification>false</remoteNotification>
<reservedSpace>true</reservedSpace>
<fsmRealTime>false</fsmRealTime>
<fsmMemLocked>false</fsmMemLocked>
<opHangLimitSecs>180</opHangLimitSecs>
<perfectFitSize>131072</perfectFitSize>
<quotas>false</quotas>
<restoreJournal>false</restoreJournal>
<restoreJournalDir></restoreJournalDir>
<restoreJournalMaxHours>0</restoreJournalMaxHours>
<restoreJournalMaxMb>0</restoreJournalMaxMb>
<stripeAlignSize>-1</stripeAlignSize>
<trimOnClose>0</trimOnClose>
<threadPoolSize>32</threadPoolSize>
<unixDirectoryCreationModeOnWindows>755</unixDirectoryCreationModeOnWindows>
<unixIdFabricationOnWindows>false</unixIdFabricationOnWindows>
<unixFileCreationModeOnWindows>644</unixFileCreationModeOnWindows>
<unixNobodyUidOnWindows>60001</unixNobodyUidOnWindows>
<unixNobodyGidOnWindows>60001</unixNobodyGidOnWindows>
<windowsSecurity>true</windowsSecurity>
<eventFiles>true</eventFiles>
<eventFileDir></eventFileDir>
<allocSessionReservationSize>0</allocSessionReservationSize>
</globals>
<diskTypes>
<diskType typeName="MetaDrive" sectors="99999999" sectorSize="512"/>
<diskType typeName="JournalDrive" sectors="99999999" sectorSize="512"/>
<diskType typeName="VideoDrive" sectors="99999999" sectorSize="512"/>
<diskType typeName="AudioDrive" sectors="99999999" sectorSize="512"/>
<diskType typeName="DataDrive" sectors="99999999" sectorSize="512"/>
</diskTypes>
<stripeGroups>
<stripeGroup index="0" name="MetaFiles" status="up" stripeBreadth="262144" read="true" write="true" metadata="true" journal="false" userdata="false" realTimeIOs="0" realTimeIOsReserve="0" realTimeMB="0" realTimeMBReserve="0" realTimeTokenTimeout="0" multipathMethod="rotate">
<disk index="0" diskLabel="CvfsDisk0" diskType="MetaDrive" ordinal="0"/>
</stripeGroup>
<stripeGroup index="1" name="JournFiles" status="up" stripeBreadth="262144" read="true" write="true" metadata="false" journal="true" userdata="false" realTimeIOs="0" realTimeIOsReserve="0" realTimeMB="0" realTimeMBReserve="0" realTimeTokenTimeout="0" multipathMethod="rotate">
<disk index="0" diskLabel="CvfsDisk1" diskType="JournalDrive" ordinal="1"/>
</stripeGroup>
<stripeGroup index="2" name="VideoFiles" status="up" stripeBreadth="4194304" read="true" write="true" metadata="false" journal="false" userdata="true" realTimeIOs="0" realTimeIOsReserve="0" realTimeMB="0" realTimeMBReserve="0" realTimeTokenTimeout="0" multipathMethod="rotate">
<affinities exclusive="true">
<affinity>Video</affinity>
</affinities>
<disk index="0" diskLabel="CvfsDisk2" diskType="VideoDrive" ordinal="2"/>
<disk index="1" diskLabel="CvfsDisk3" diskType="VideoDrive" ordinal="3"/>
<disk index="2" diskLabel="CvfsDisk4" diskType="VideoDrive" ordinal="4"/>
<disk index="3" diskLabel="CvfsDisk5" diskType="VideoDrive" ordinal="5"/>
<disk index="4" diskLabel="CvfsDisk6" diskType="VideoDrive" ordinal="6"/>
<disk index="5" diskLabel="CvfsDisk7" diskType="VideoDrive" ordinal="7"/>
<disk index="6" diskLabel="CvfsDisk8" diskType="VideoDrive" ordinal="8"/>
<disk index="7" diskLabel="CvfsDisk9" diskType="VideoDrive" ordinal="9"/>
</stripeGroup>
<stripeGroup index="3" name="AudioFiles" status="up" stripeBreadth="1048576" read="true" write="true" metadata="false" journal="false" userdata="true" realTimeIOs="0" realTimeIOsReserve="0" realTimeMB="0" realTimeMBReserve="0" realTimeTokenTimeout="0" multipathMethod="rotate">
<affinities exclusive="true">
<affinity>Audio</affinity>
</affinities>
<disk index="0" diskLabel="CvfsDisk10" diskType="AudioDrive" ordinal="10"/>
<disk index="1" diskLabel="CvfsDisk11" diskType="AudioDrive" ordinal="11"/>
<disk index="2" diskLabel="CvfsDisk12" diskType="AudioDrive" ordinal="12"/>
<disk index="3" diskLabel="CvfsDisk13" diskType="AudioDrive" ordinal="13"/>
</stripeGroup>
<stripeGroup index="4" name="RegularFiles" status="up" stripeBreadth="262144" read="true" write="true" metadata="false" journal="false" userdata="true" realTimeIOs="0" realTimeIOsReserve="0" realTimeMB="0" realTimeMBReserve="0" realTimeTokenTimeout="0" multipathMethod="rotate">
<disk index="0" diskLabel="CvfsDisk14" diskType="DataDrive" ordinal="14"/>
<disk index="1" diskLabel="CvfsDisk15" diskType="DataDrive" ordinal="15"/>
<disk index="2" diskLabel="CvfsDisk16" diskType="DataDrive" ordinal="16"/>
<disk index="3" diskLabel="CvfsDisk17" diskType="DataDrive" ordinal="17"/>
</stripeGroup>
</stripeGroups>
</config>
</configDoc>
I know, I know. It’s not as pretty as the flat files were, but it’s much easier to parse. But let’s look at something simpler. Let’s just validate a volume’s config using sncfgvalidate:
/System/Library/Filesystems/acfs.fs/Contents/bin/sncfgvalidate -n MYVOLUME
Cute, we should just get back a response that:
'MYVOLUME' validated
I don’t know if you feel validated but I sure do. Running sncfg allows you to edit a filesystem (use -n to specify the name of the filesystem and -f to specify a temp file to write changes to in case the edit fails. sncfgconvert can convert a config file into an XML or ASCII file (choose using -F) using a -f option to identify the source file, -n to identify the name of your filesystem and -v to do it all with verbosity (been waiting all day to use that word!). The sncfgremove is somewhat dangerous allowing you to remove filesystems and the sncfginstall is somewhat interesting as it allows you to install filesystems as easily as you removed them. The sndpscfg configures the StorNext Disk Proxy Server, which I can’t seem to get to work just yet (although it is compiled for OS X as it calls the paths that we use for StorNext for logs and the such).
Then there’s sncfgquery, which seems to not be fully implemented as it won’t yet let me send actions to the command. Once it does you should be able to send a Dump, List and Query action in order to check various things about the SAN. Seems as though a lot of errors could be diagnosed, such as having a pool with no specified purpose, not having a .auth_secret available, etc.
Finally, this article isn’t going to be very useful yet. But it does show that there’s change brewing under Xsan’s hood. Changes that you can see in regards to newer implementations of StorNext not only being more compatible but also feeding into Xsan as well. Hopefully that means more features and more feature compatibility as time goes on!