<!-- 
RSS generated by JIRA (9.4.14#940014-sha1:734e6822bbf0d45eff9af51f82432957f73aa32c) at Sat Feb 10 02:57:42 UTC 2024

It is possible to restrict the fields that are returned in this document by specifying the 'field' parameter in your request.
For example, to request only the issue key and summary append 'field=key&field=summary' to the URL of your request.
-->
<rss version="0.92" >
<channel>
    <title>Whamcloud Community JIRA</title>
    <link>https://jira.whamcloud.com</link>
    <description>This file is an XML representation of an issue</description>
    <language>en-us</language>    <build-info>
        <version>9.4.14</version>
        <build-number>940014</build-number>
        <build-date>05-12-2023</build-date>
    </build-info>


<item>
            <title>[LU-13024] Lustre HSM support for a directory&#160;</title>
                <link>https://jira.whamcloud.com/browse/LU-13024</link>
                <project id="10000" key="LU">Lustre</project>
                    <description>&lt;p&gt;Currently Lustre only supports HSM for a regular file. There is a growing demand to add Lustre HSM support for a directory to meet the potential requirements coming from PCC and WBC.&lt;/p&gt;

&lt;p&gt;The draft proposal design could be as follows:&lt;/p&gt;
&lt;h2&gt;&lt;a name=&quot;lfshsmarchive%24DIR&quot;&gt;&lt;/a&gt;lfs hsm_archive $DIR&lt;/h2&gt;

&lt;p&gt;Before archive the directory $DIR, it must ensure that there are no any locks granted to clients for all sub directories and files under the directory $DIR on MDT.&lt;br/&gt;
 It could be achieved:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;b&gt;HSMDIR(DIR)&lt;/b&gt;:&lt;br/&gt;
 HSM naming structure on HSM backend for a Lustre directory DIR:&lt;br/&gt;
 &quot;%04x/%04x/%04x/%04x/%04x/%04x/&quot; DFID_NOBRACE FID(DIR)&lt;/li&gt;
	&lt;li&gt;&lt;b&gt;Version(entry)&lt;/b&gt;:&lt;br/&gt;
 version of the metadata object, could be same as version number used by COS;&lt;/li&gt;
	&lt;li&gt;&lt;b&gt;DataVersion(entry)&lt;/b&gt;:&lt;br/&gt;
 Data version of the regular file @entry, return 0 if @entry is not a regular file;&lt;/li&gt;
	&lt;li&gt;&lt;b&gt;FID(entry)&lt;/b&gt;: FID of the file @entry;&lt;/li&gt;
	&lt;li&gt;&lt;b&gt;LayoutGen(entry)&lt;/b&gt;:&lt;br/&gt;
 Layout generation of the regular file @entry;&lt;/li&gt;
	&lt;li&gt;&lt;b&gt;HsmVersion(hsmcopy):&lt;/b&gt;&lt;br/&gt;
 Field of EA for HSM copy - hsmcopy.hsm_meta_ver&lt;/li&gt;
	&lt;li&gt;&lt;b&gt;HsmDataversion(hsmcopy):&lt;/b&gt;&lt;br/&gt;
 Field of EA for HSM copy - hsmcopy.hsm_data_ver&lt;/li&gt;
	&lt;li&gt;&lt;b&gt;HsmLayoutGen(hsmcopy):&lt;/b&gt;&lt;br/&gt;
 Field of EA for HSM copy - hsmcopy.hsm_layout_gen;&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&quot;code panel&quot; style=&quot;border-width: 1px;&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot;&gt;
&lt;pre class=&quot;code-java&quot;&gt;
Revoke_subtree_locks(dir) { 
    &lt;span class=&quot;code-keyword&quot;&gt;for&lt;/span&gt; entry in dir {
        AcquireLock(entry, LCK_EX);
        &lt;span class=&quot;code-keyword&quot;&gt;if&lt;/span&gt; (entry-&amp;gt;d_type == DT_DIR)
            Revoke_subtree_locks(entry);
        ReleaseLock(entry, LCK_EX);
   }
}
AcquireLock(DIR, LCK_EX);
Revoke_subtree_locks(DIR);

Copy_files(): {
    If use POSIX copytool (lhsm_posix), create a directory according to HSM naming structure on HSM backend:
HSMDIR(DIR): &lt;span class=&quot;code-quote&quot;&gt;&quot;%04x/%04x/%04x/%04x/%04x/%04x/&quot;&lt;/span&gt; DFID_NOBRACE FID(DIR)
The copytool copies all directories and files under $DIR into HSM HSMDIR(DIR).
Here we may need to a special open flag O_IGNORE_IBITS_LOCK | O_IGNORE_EXTENT_LOCK (similar to O_LOV_DELAY_CREATE) to indicate that operations such as open/close, readdir(), read()/write() should not take any lock (lockless IO &lt;span class=&quot;code-keyword&quot;&gt;for&lt;/span&gt; metadata or data IO).
Meanwhile, we define a data structure named hsm_copy_attrs to store the necessary information in the EA of HSM copy:
&lt;span class=&quot;code-comment&quot;&gt;/*&#160; HSM on-disk attributes stored in a separate xattr &lt;span class=&quot;code-keyword&quot;&gt;for&lt;/span&gt; HSM copy.&#160;*/&lt;/span&gt;
struct hsm_copy_attrs
{ 
    &lt;span class=&quot;code-comment&quot;&gt;/* Bitfield &lt;span class=&quot;code-keyword&quot;&gt;for&lt;/span&gt; supported data in &lt;span class=&quot;code-keyword&quot;&gt;this&lt;/span&gt; structure. For &lt;span class=&quot;code-keyword&quot;&gt;future&lt;/span&gt; use. */&lt;/span&gt; 
    __u32 hsm_compat;
    &lt;span class=&quot;code-comment&quot;&gt;/* HSM flags, see hsm_flags &lt;span class=&quot;code-keyword&quot;&gt;enum&lt;/span&gt; below */&lt;/span&gt; 
    __u32 hsm_flags;
    &lt;span class=&quot;code-comment&quot;&gt;/* backend archive id associated with the file */&lt;/span&gt;
    __u64 hsm_arch_id;
    &lt;span class=&quot;code-comment&quot;&gt;/* version associated with the last archiving, &lt;span class=&quot;code-keyword&quot;&gt;if&lt;/span&gt; any */&lt;/span&gt;
    __u64 hsm_data_ver; &lt;span class=&quot;code-comment&quot;&gt;/* data version Only used &lt;span class=&quot;code-keyword&quot;&gt;for&lt;/span&gt; regular files */&lt;/span&gt;
    __u64&#160;hsm_meta_ver; &lt;span class=&quot;code-comment&quot;&gt;/* version of metadata used by COS */&lt;/span&gt;
    __u64 hsm_layout_gen; &lt;span class=&quot;code-comment&quot;&gt;/* layout generation only &lt;span class=&quot;code-keyword&quot;&gt;for&lt;/span&gt; regular files */&lt;/span&gt;
    &lt;span class=&quot;code-comment&quot;&gt;/* original fid &lt;span class=&quot;code-keyword&quot;&gt;if&lt;/span&gt; want to keep FID unchanged after restore */&lt;/span&gt;
    struct lu_fid&#160; hsm_fid;
};

Once copy a file or a directory @entry into HSM, set the corresponding HSM attrs (data structure hsm_copy_attrs)&lt;span class=&quot;code-keyword&quot;&gt;for&lt;/span&gt; the PCC copy in a form of EA: 
    hsmcopy.hsm_data_ver = DataVersion(entry); &lt;span class=&quot;code-comment&quot;&gt;// 0 &lt;span class=&quot;code-keyword&quot;&gt;for&lt;/span&gt; directory
&lt;/span&gt;    hsmcopy.hsm_meta_ver = Version(entry);
    hsmcopy.hsm_layout_gen = LayoutGen(entry);
    hsmcopy.hsm_fid = FID(entry);
}

ReleaseLock(DIR, LCK_EX);
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;&lt;a name=&quot;lfshsmrelease%24DIR&quot;&gt;&lt;/a&gt;lfs hsm_release $DIR&lt;/h2&gt;
&lt;div class=&quot;code panel&quot; style=&quot;border-width: 1px;&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot;&gt;
&lt;pre class=&quot;code-java&quot;&gt;
&#160;
CheckReleaseDir(dir, hsmbasedir){
    &lt;span class=&quot;code-keyword&quot;&gt;if&lt;/span&gt; (Version(dir) != HsmVersion(hsmbasedir)) {
       &lt;span class=&quot;code-comment&quot;&gt;// dir was modified.
&lt;/span&gt;       &lt;span class=&quot;code-comment&quot;&gt;// resync @dir and @hsmbasedir
&lt;/span&gt;       forall: &lt;span class=&quot;code-keyword&quot;&gt;if&lt;/span&gt; one child directory or file in @hsmbasedir is not in @dir:
                  remove &lt;span class=&quot;code-keyword&quot;&gt;this&lt;/span&gt; child directory or file
       fi
       forall: &lt;span class=&quot;code-keyword&quot;&gt;if&lt;/span&gt; one child directory or file in @dir is not in @hsmbasedir:
                  Copy_file();
       fi
    }
    &lt;span class=&quot;code-comment&quot;&gt;// after resync above, two directories should be consistent. 
&lt;/span&gt;    &lt;span class=&quot;code-keyword&quot;&gt;for&lt;/span&gt; entry in dir {
        AcquireLock(entry, LCK_EX); 
        hsment = hsmbasedir + &lt;span class=&quot;code-quote&quot;&gt;&quot;/&quot;&lt;/span&gt; + entry; 
        &lt;span class=&quot;code-keyword&quot;&gt;if&lt;/span&gt; (Version(entry) != HsmVersion(hsment)
            resync metadata attributes which may be changed;
        &lt;span class=&quot;code-keyword&quot;&gt;if&lt;/span&gt; (entry-&amp;gt;d_type == DT_REGULAR) { 
             &lt;span class=&quot;code-keyword&quot;&gt;if&lt;/span&gt; (LayoutGen(entry) != HsmLayoutGen(hsment) ||
                  DataVersion(entry) != HsmDataVersion(hsment)) {
                       resync data;
            } 
       } &lt;span class=&quot;code-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;code-keyword&quot;&gt;if&lt;/span&gt; (entry-&amp;gt;d_type == DI_DIR) {
                  CheckReleaseDir(dir + &lt;span class=&quot;code-quote&quot;&gt;&quot;/&quot;&lt;/span&gt; + entry, hsment);
       } 
       ReleaseLock(entry, LCK_EX);
       delete @entry from Lustre file system;
 }
 
When &lt;span class=&quot;code-keyword&quot;&gt;try&lt;/span&gt; to lock @dir, it still need to check whether @DIR is currently keeping opened, &lt;span class=&quot;code-keyword&quot;&gt;if&lt;/span&gt; so, stop HSM release &lt;span class=&quot;code-keyword&quot;&gt;for&lt;/span&gt; the directory.

AcquireLock(DIR, LCK_EX);
CheckReleaseDir(DIR, HSMDIR(DIR));
ReleaseLock(DIR, LCK_EX);
&#160;&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;&lt;a name=&quot;lfshsmremove%24DIR&quot;&gt;&lt;/a&gt;lfs hsm_remove $DIR&lt;/h2&gt;

&lt;p&gt;Remove the archived HSMDIR($DIR) entirely from HSM;&lt;/p&gt;
&lt;h2&gt;&lt;a name=&quot;lfshsmrestore%24DIR&quot;&gt;&lt;/a&gt;lfs hsm_restore $DIR&lt;/h2&gt;

&lt;p&gt;$DIR should be an empty directory in Lustre file system.&lt;br/&gt;
 AcquireLock(DIR, LCK_EX);&lt;br/&gt;
 RestoreDir(DIR, HSMDIR(DIR), level)&lt;br/&gt;
 ReleaseLock(DIR, LCK_EX);&lt;br/&gt;
 Similar to archive, when restore a directory, we should also use open flags O_IGNORE_IBITS_LOCK | O_IGNORE_EXTENT_LOCK to create files and resync data without taking any locks.&lt;br/&gt;
 During restore, we could restore level by level:&lt;/p&gt;
&lt;div class=&quot;code panel&quot; style=&quot;border-width: 1px;&quot;&gt;&lt;div class=&quot;codeContent panelContent&quot;&gt;
&lt;pre class=&quot;code-java&quot;&gt;
@dir: Lustre directory which is HSM released;
@hsmdir: the corresponding HSMDIR(dir);
@level: directory level to restore
RestoreDir(dir, hsmdir, level){
    &lt;span class=&quot;code-keyword&quot;&gt;for&lt;/span&gt; entry in hsmdir {
         pathname = dir + &lt;span class=&quot;code-quote&quot;&gt;&quot;/&quot;&lt;/span&gt; + entry;
         create(pathname, O_IGNORE_IBITS_LOCK | O_IGNORE_EXTENT_LOCK | O_DIRECT); 
         &lt;span class=&quot;code-keyword&quot;&gt;if&lt;/span&gt; (level &amp;lt;= 0) {
             fid = FID(pathname);
             mv hsmdir/entry HSMDIR(fid);
             set Lustre file @pathname with HSM released
         } &lt;span class=&quot;code-keyword&quot;&gt;else&lt;/span&gt; {
             &lt;span class=&quot;code-keyword&quot;&gt;if&lt;/span&gt; (entry-&amp;gt;d_type == DT_REGULAR) {
                  restore data from hsmdir/entry to @pathname;
             } &lt;span class=&quot;code-keyword&quot;&gt;else&lt;/span&gt; {
                  RestoreDir(dir/entry, hsmdir/entry, level - 1);
             }
       }
 }
}
&lt;/pre&gt;
&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;&lt;a name=&quot;IncrementalbackupforaLustresubtreeviaHSMarchive&quot;&gt;&lt;/a&gt;Incremental backup for a Lustre subtree via HSM archive&lt;/h2&gt;

&lt;p&gt;&lt;b&gt;lfs hsm_archive -i archive_id --tag $TAG $DIR&lt;/b&gt;&lt;br/&gt;
 Via HSM archive for a directory, we could backup a Lustre subtree into HSM backend;&lt;br/&gt;
 If we want to save space usage, we can event release a Lustre subtree once it was archived;&lt;br/&gt;
 We could add tag to implement incremental backup where @tag could be monotonically increasing number (version) or timestamp when to backup.&lt;br/&gt;
 If the HSM backend, which is determined by archive_id, are same for archives with different tags, we can event reuse the backup data with same metadata version number for directories in the HSM archive or same data version and layout generation for regular files in the HSM archive.&lt;br/&gt;
 Of course, we could also restore dedicated archive into a dedicated destination directory as follows:&lt;br/&gt;
 &lt;b&gt;lfs hsm_restore --tag $TAG --dest $TARGET $DIR&lt;/b&gt;&lt;/p&gt;</description>
                <environment></environment>
        <key id="57486">LU-13024</key>
            <summary>Lustre HSM support for a directory&#160;</summary>
                <type id="2" iconUrl="https://jira.whamcloud.com/secure/viewavatar?size=xsmall&amp;avatarId=11311&amp;avatarType=issuetype">New Feature</type>
                                            <priority id="4" iconUrl="https://jira.whamcloud.com/images/icons/priorities/minor.svg">Minor</priority>
                        <status id="1" iconUrl="https://jira.whamcloud.com/images/icons/statuses/open.png" description="The issue is open and ready for the assignee to start work on it.">Open</status>
                    <statusCategory id="2" key="new" colorName="default"/>
                                    <resolution id="-1">Unresolved</resolution>
                                        <assignee username="wc-triage">WC Triage</assignee>
                                    <reporter username="qian_wc">Qian Yingjin</reporter>
                        <labels>
                    </labels>
                <created>Wed, 27 Nov 2019 16:38:44 +0000</created>
                <updated>Thu, 28 Nov 2019 03:58:19 +0000</updated>
                                                                                <due></due>
                            <votes>0</votes>
                                    <watches>7</watches>
                                                                            <comments>
                            <comment id="258942" author="adilger" created="Thu, 28 Nov 2019 03:58:19 +0000"  >&lt;p&gt;I think one of the important considerations for HSM archiving a whole directory is that it needs to be efficient in terms of handling lots of small files (potentially HSM stubs for already-archived large files).  I think the right approach for this is to use Client Container Images (CCI) to archive a directory tree (see &lt;a href=&quot;https://www.eofs.eu/_media/events/lad19/05_andreas_dilger-lustre_2.14_and_beyond.pdf&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;LAD&apos;19 Lustre 2.14 and Beyond&lt;/a&gt;, essentially an ext4 filesystem image that can be created with &quot;&lt;tt&gt;mke2fs -d &amp;lt;dir&amp;gt;&lt;/tt&gt;&quot; to populate the image at format time from the source directory, and then release the files in the directory tree.  By packing many small files/stubs into a single image file, this can efficiently be stored on an OST, and/or archived to tape, unlike processing thousands or millions of small files. Handling all of the files in an archived directory as a single file will run at the IO bandwidth of large files (GB/s = Mfiles/s). &lt;/p&gt;

&lt;p&gt;I&apos;d originally thought about using a tar file to store the archived directory tree, but an ext4 (or ldiskfs) image is much more useful in a number of ways:&lt;/p&gt;
&lt;ul class=&quot;alternate&quot; type=&quot;square&quot;&gt;
	&lt;li&gt;the ext4 image can be loopback mounted directly from the image file and accessed in read-write mode, unlike a tarball that has to be extracted completely before it is modified and then tarred up again.&lt;/li&gt;
	&lt;li&gt;the ext4 image can be mounted directly by the MDS at the appropriate mountpoint and exported to clients for access in a shared manner&lt;/li&gt;
	&lt;li&gt;ext4 images are more robust containers than tar files, since they can be checked and repaired with e2fsck, have embedded metadata checksums (and soon fsverify data checksums), and have redundant metadata to help repairs.&lt;/li&gt;
	&lt;li&gt;the ext4/ldiskfs format can hold all of the important Lustre metadata efficiently, and can be mounted directly by the ldiskfs module, which we can modify as needed to maintain proper Lustre state in the image if needed.&lt;/li&gt;
&lt;/ul&gt;
</comment>
                    </comments>
                    <attachments>
                    </attachments>
                <subtasks>
                    </subtasks>
                <customfields>
                                                                                                                                                                <customfield id="customfield_10890" key="com.atlassian.jira.plugins.jira-development-integration-plugin:devsummary">
                        <customfieldname>Development</customfieldname>
                        <customfieldvalues>
                            
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                        <customfield id="customfield_10390" key="com.pyxis.greenhopper.jira:gh-lexo-rank">
                        <customfieldname>Rank</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>1|i00q33:</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_10090" key="com.pyxis.greenhopper.jira:gh-global-rank">
                        <customfieldname>Rank (Obsolete)</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>9223372036854775807</customfieldvalue>
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                </customfields>
    </item>
</channel>
</rss>