<?xml version="1.0" encoding="US-ASCII"?>
<!DOCTYPE rfc SYSTEM "rfc2629.dtd">
<?rfc toc="yes"?>
<?rfc tocompact="yes"?>
<?rfc tocdepth="3"?>
<?rfc tocindent="yes"?>
<?rfc symrefs="yes"?>
<?rfc sortrefs="yes"?>
<?rfc comments="yes"?>
<?rfc inline="yes"?>
<?rfc compact="yes"?>
<?rfc subcompact="no"?>
<rfc category="std" docName="draft-mzhang-nfsv4-recursively-setting-01"
     ipr="trust200902">
  <front>
    <title abbrev="Recursively Setting Directoriestle">Recursively Setting
    Directories and Subitems</title>

    <author fullname="Minqian Zhang" initials="M." surname="Zhang">
      <organization>Huawei Technologies</organization>

      <address>
        <postal>
          <street>1899 Xiyuan</street>

          <city>Chengdu</city>

          <code>611731</code>

          <region>High-tech West District</region>

          <country>China</country>
        </postal>

        <phone>+86-13547833949</phone>

        <facsimile/>

        <email>zhangmingqian.zhang@huawei.com</email>
      </address>
    </author>

    <author fullname="Sunil Kumar Bhargo" initials="M." surname="Bhargo">
      <organization>VMware</organization>

      <address>
        <postal>
          <street/>
        </postal>

        <phone>+</phone>

        <facsimile/>

        <email>marx_bhargav@yahoo.com</email>
      </address>
    </author>

    <author fullname="Rijesh Kunhi Parambattu" initials="R."
            surname="Parambattu">
      <organization>Huawei Technologies</organization>

      <address>
        <postal>
          <street/>

          <city/>

          <code/>

          <region/>

          <country/>
        </postal>

        <phone/>

        <facsimile/>

        <email>rijesh.kunhi.parambattu1@huawei.com</email>
      </address>
    </author>

    <author fullname="Dongyu Geng" initials="D." surname="Geng">
      <organization>Huawei Technologies</organization>

      <address>
        <postal>
          <street/>

          <city/>

          <code/>

          <region/>

          <country/>
        </postal>

        <phone/>

        <facsimile/>

        <email>gengdongyu@huawei.com</email>
      </address>
    </author>

    <author fullname="Yunfei Du" initials="Y." surname="Du">
      <organization>Huawei Technologies</organization>

      <address>
        <postal>
          <street/>

          <city/>

          <code/>

          <region/>

          <country/>
        </postal>

        <phone/>

        <facsimile/>

        <email>duyunfei1@huawei.com</email>
      </address>
    </author>

    <date day="25" month="March" year="2024"/>

    <area>Transport Area</area>

    <workgroup>Network File System Version 4</workgroup>

    <keyword>Recursively setting</keyword>

    <abstract>
      <t>In recent years, the concept of near-data computing has been widely
      recognized in storage architectures. The core idea is to process data
      nearby, reduce the overhead of network transmission, and utilize the
      computing capability of smart devices (such as intelligent NICs, smart
      SSDs, and DPUs). This reduces CPU and memory usage of clients (computing
      nodes) and improves data processing efficiency. This design idea is
      applied in NFSv4.2 or future NFS verions, such as Server-Side Copy, in
      which client sends the control command and the storage server copies
      data without passing through the data between the client and storage
      server. Compared with traditional copy operations, data is read from the
      source storage server and then written to the target storage server
      after two network transmissions. Data transmission on the network is
      reduced, and bandwidth resources are greatly released. In addition, the
      client changes from an original data copy executor to a data copy
      controller, and a specific execution action is executed by the storage
      server. Therefore, a large amount of computing resources and memory
      resources are saved on the client side.</t>
    </abstract>

    <note title="Requirements Language">
      <t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
      "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
      document are to be interpreted as described in <xref
      target="RFC2119">RFC 2119</xref>.</t>
    </note>
  </front>

  <middle>
    <section title="Problem Statement">
      <t>In actual storage applications, users often recursively set the
      attributes of directories and subitems(their subfiles and
      subdirectories). Message interaction between client and server is
      complex, and the client consumes a lot of resources, which does not
      match the concept of near-data computing. FIG. 1 shows the existing
      flowchart of recursively setting the attributes of all files under
      dir1.</t>

      <t>Step 1: The client sends the readdir command to obtain the list of
      all files in dir1.</t>

      <t>Step 2: The storage server responds to the readdir operation. If the
      directory contains many subitems, the client needs to run the readdir
      operation for multiple times.</t>

      <t>Step 3: The client obtains the file list based on the response
      information, executes the getattr request for each file, and obtains the
      file attributes.</t>

      <t>Step 4: The storage server responds to the getattr request.</t>

      <t>Step 5: The client sends a setattr request.</t>

      <t>Step 6: The storage server responds to the setattr request.</t>

      <t>Repeat step 1 to step 6 to traverse all files. If the dir1 directory
      contains 100,000 files, repeat step 1 to step 6 for 100,000 times to
      recursively set the dir1 attribute. It can be learned that the process
      consumes CPU resources and memory resources of the client, and a large
      number of messages are exchanged between the client and the storage
      server. As a result, an end-to-end time for the attribute setting
      operation is relatively long.</t>

      <t><figure>
          <preamble>preamble to the figure.</preamble>

          <artwork><![CDATA[      
                 Client                                Server
                 +                                       +
                 |                                       |
                 |------ Readdir ----------------------->|
                 |<--------------------------------------|
                 |------ Getattr ----------------------->|
                 |<--------------------------------------|
                 |------ Setattr ----------------------->|
                 |<--------------------------------------|
                 |         ....                          |            
                 |                                       |

        Figure 1: Existing flowchart for recursive set operation

]]></artwork>

          <postamble>As you can see, this figure doodled and
          dawdled.</postamble>
        </figure></t>
    </section>

    <section anchor="IANA" title="Protocol Overview">
      <t>After adopting the concept of near data calculation, the above
      scenario can be optimized.</t>

      <t>Step 1: The client identifies that the operation object of the
      attribute setting is a directory and the attribute setting is recursive,
      and invokes a new operation (for example, RECURSIVE_SET).</t>

      <t>Step 2: The storage server recursively queries all files in the
      directory, sets attributes for each file, and sends a RECURSIVE_SET
      response.</t>

      <t>Compared with the original process, this process not only saves the
      CPU and memory usage of the client, but also significantly reduces the
      number of messages exchanged between the client and server. This greatly
      improves the efficiency in recursive attribute setting scenarios.</t>

      <t>Similar to the design of Server-Side Copy, the new operation word
      RECURSIVE_SET is used to recursively set the attributes of a directory
      and its subitems. This operation can be in synchronous or asynchronous
      mode, which is determined by the input parameter:</t>

      <t>o If no back channel is created when the client and server establish
      a connection, the client can only use the synchronous mode in the
      RECURSIVE_SET request. If the client uses the asynchronous mode, the
      server returns the error code NFS4ERR_CB_PATH_DOWN.</t>

      <t>o If a back channel is created when the client and server establish a
      connection, the RECURSIVE_SET request can be in synchronous or
      asynchronous mode.</t>

      <t>Note to RFC Editor: this section may be removed on publication as an
      RFC.</t>
    </section>

    <section anchor="Security" title="Implementation Considerations">
      <t>A recommended Recursive Set operation in an synchronous mode is shown
      in Figure 2.</t>

      <t>Step 1: The client sends a RECURSIVE_SET request. In the request,
      select the synchronization setting mode and set rsa_sync to true.</t>

      <t>Step 2: If the storage server completes the setting within the
      timeout period, the storage server returns the request result to the
      client. If the setting is not complete within the timeout period,
      generate rsr_callback_id and rsr_recursiveverf. In addition, the
      rsr_callback_id, rsr_recursiveverf, and error code are sent to the
      client.</t>

      <t>Step 3: The client sends a RECURSIVE_SET_STATUS query request. The
      request contains the information of rss_stateid. The value of
      rss_stateid is obtained from the response packet of RECURSIVE_SET which
      value is the value rsr_callback_id. If the value of rss_stateid is the
      same as the value of rsr_callback_id cached on the storage server, the
      storage server returns the setting result. Storage server return NFS4_OK
      if the server successfully finish the recursive setting or NFS4_Pending
      if the setting is till on going, or else set failure error code. If the
      value of rss_stateid in the request is different from the value cached
      on the server, the storage server returns the error code
      NFS4ERR_BAD_STATEID.</t>

      <t>Step 4: After receiving the RECURSIVE_SET_STATUS response, the client
      delays sending the RECURSIVE_SET_STATUS request if the error code is
      NFS4_PENDING. The delay setting request must contain rss_stateid. If the
      error code returned by the server is NFS4_OK, the recursive attribute
      setting is successful. If the error code is the error code of setattr
      defined in NFSv4.2, the recursive attribute setting fails. In this case,
      the client returns a response to the application.</t>

      <t><figure>
          <preamble>preamble to the figure.</preamble>

          <artwork><![CDATA[      
                 Client                                                 Server
                 +                                                         +
                 |                                                         |
                 |------ RECURSIVE_SET(rsa_sync = 1) --------------------->|
                 |                                                         |
                 |<-----Response(rsr_callback_id=0, rsr_recursiveverf=0)---|  within the timeout period
                 |                                                         |  
                 |                                                         |
                 |<----Response(rsr_callback_id=1, rsr_recursiveverf=1)----|  beyond the timeout period
                 |                                                         |  
                 |                                                         |
                 |                                                         |
                 |-------RECURSIVE_SET_STATUS(rss_stateid=1)-------------->|
                 |                                                         |
                 |<------Response------------------------------------------|
                 |                                                         |   
                 |                                                         |          

                   Figure 2:  A synchronous Recursive Set

]]></artwork>

          <postamble>As you can see, this figure doodled and
          dawdled.</postamble>
        </figure>An alternative Recursive Set operation in an synchronous mode
      is also given in Figure 3.</t>

      <t>Step 1: The client sends a RECURSIVE_SET request. In the request,
      select the synchronization setting mode and set rsa_sync to true.</t>

      <t>Step 2: If the storage server completes the setting within the
      timeout period, the storage server returns the request result to the
      client. If the setting is not complete within the timeout period,
      generate rsr_callback_id and rsr_recursiveverf, and set the error code
      to NFS4_PENDING. In addition, the rsr_callback_id, rsr_recursiveverf,
      and error code are sent to the client.</t>

      <t>Step 3: The client sends a RECURSIVE_SET_STATUS query request. The
      request contains the information of rss_stateid. The value of
      rss_stateid is obtained from the response packet of RECURSIVE_SET which
      value is the value rsr_callback_id. If the value of rss_stateid is the
      same as the value of rsr_callback_id cached on the storage server, the
      storage server returns the setting result. (if Success, set
      NFS4_Pending, or else set failure error code). If the value of
      rss_stateid in the request is different from the value cached on the
      server, the storage server returns the error code
      NFS4ERR_BAD_STATEID.</t>

      <t>Step 4: After receiving the RECURSIVE_SET response, the client delays
      sending the RECURSIVE_SET_STATUS request if the error code is
      NFS4_PENDING. The delay setting request must contain rss_stateid. If the
      error code returned by the server is NFS4_OK, the recursive attribute
      setting is successful. If the error code is the error code of setattr
      defined in NFSv4.2, the recursive attribute setting fails. In this case,
      the client returns a response to the application.</t>

      <t>A recommended Recursive Set operation in an asynchronous mode is
      shown in Figure 3.</t>

      <t>Step 1: The client sends a RECURSIVE_SET request. In the request, the
      asynchronous setting mode is rsa_sync=false.</t>

      <t>Step 2: The storage server needs to generate rsr_callback_id and
      rsr_recursiveverf, and set the error code to NFS4_OK. In addition, the
      rsr_callback_id, rsr_recursiveverf, and error code are sent to the
      client. The storage server continues the recursive setting
      operation.</t>

      <t>Step 3: After receiving the response, the client checks the error
      code and starts an asynchronous task to receive the callback message
      from the server.</t>

      <t>Step 4: The client create an asynchronous listening task and matches
      rsr_callback_id and rsr_recursiveverf. If the matching succeeds, the
      task is successfully executed. If rsr_callback_id can be matched but
      rsr_recursiveverf cannot be matched, client skip the message.</t>

      <t>Step 5: After recursively setting attributes, the storage server
      sends a message to the client through the backchannel of the NFS4 and
      notifies the client of the setting result.</t>

      <t>Step 6: If the client does not receive the asynchronous message, the
      started task is forcibly terminated when the session is destroyed. If an
      error occurs when the storage server recursively sets subitem
      attributes, the storage server terminates the task and returns the error
      code to the client. All possible errors are subject to the error codes
      defined by setattr.</t>

      <t><figure>
          <preamble>preamble to the figure.</preamble>

          <artwork><![CDATA[   
                 Client                                                 Server
                 +                                                         +
                 |                                                         |
                 |------ RECURSIVE_SET(rsa_sync = 0) --------------------->|
                 |                                                         |
                 |<------Response(rsr_callback_id=1, rsr_recursiveverf=1)--|  
                 |                                                         |  
                 |                                                         |
                 |<------CB_RECURSIVE_SET----------------------------------|
                 |                                                         | 
                 |                                                         |
                 |                                                         |

                   Figure 3: An asynchronous Recursive Set

]]></artwork>

          <postamble>As you can see, this figure doodled and
          dawdled.</postamble>
        </figure></t>

      <t/>
    </section>

    <section anchor="Acknowledgements" title="Recursive Set Operations">
      <t>4.1 Operation TBD1: RECURSIVE_SET &ndash; Recursively sets the
      attributes of a directory and its subitems</t>

      <t>ARGUMENT</t>

      <t>&lt;CODE BEGINS&gt;</t>

      <t>Struct RECURSIVE_SET4args {</t>

      <t>bool rsa_sync;</t>

      <t>};</t>

      <t>&lt;CODE ENDS&gt;</t>

      <t>RESULT</t>

      <t>&lt;CODE BEGINS&gt;</t>

      <t>struct recursive_set_response4 {</t>

      <t>stateid4 rsr_callback_id;</t>

      <t>verifier4 rsr_recursiversr_recursiveverf;</t>

      <t>};</t>

      <t>union RECURSIVE_SET4res (nfsstat4 rsr_status) {</t>

      <t>case NFS4_OK:</t>

      <t>recursive_set_response4 rsr_resok4;</t>

      <t>default:</t>

      <t>void;</t>

      <t>};</t>

      <t>&lt;CODE ENDS&gt;</t>

      <t>DESCRIPTION</t>

      <t>The RECURSIVE_SET operation is used by the client to recursively set
      the attributes of a directory and all its subitems. The operation should
      be placed after setattr in the existing setattr operation. After the
      storage server receives the setattr combination operation, if the
      setattr operation does not followed by RECURSIVE_SET, the original
      process remains unchanged. If the setattr operator is followed by the
      RECURSIVE_SET operation, the storage server considers the attributes of
      the directory and its subitems to initiate recursive set mode.</t>

      <t>If the storage is successfully executed, the values of
      rsr_callback_id and rsr_recursiversr_recursiveverf are 0.</t>

      <t>If the storage is not complete, the values of rsr_callback_id and
      rsr_recursiversr_recursiveverf are generated.</t>

      <t>If rsa_sync is set to true, there are two processing policies:</t>

      <t>o According to the NFSv4 protocol, the client must wait for the
      response from the server. Therefore, the client can wait for the
      processing result from the server. A problem in this mode is that the
      current request occupies a slot in a session, resulting in a decrease in
      the number of available slots. If multiple tasks of the same type are
      being executed, no slot is available on the client in severe cases.</t>

      <t>o The storage server determines the implementation duration. If the
      implementation duration is too long, the storage server may return
      non-zero values of rsr_callback_id and
      rsr_recursiversr_recursiveverf.</t>

      <t>After the client receives the request, the client waits for a period
      of time and executes RECURSIVE_SET_STATUS to query the execution
      progress of the current task. If the server does not finish the
      execution , NFS4ERR_PENDING is returned. After receiving the error code,
      the client retryes the query after a period of time. If the execution is
      complete, NFS4_OK is returned.</t>

      <t/>

      <t>4.2 Operation TBD2: RECURSIVE_SET_STATUS &ndash; Query the result of
      the recursively setting the attributes of directories and their
      subitems</t>

      <t>ARGUMENT</t>

      <t>&lt;CODE BEGINS&gt;</t>

      <t>struct RECURSIVE_SET_STATUS4args {</t>

      <t>stateid4 rssa_stateid;</t>

      <t>};</t>

      <t>&lt;CODE ENDS&gt;</t>

      <t>RESULT</t>

      <t>&lt;CODE BEGINS&gt;</t>

      <t>#define NFS4ERR_PENDING 10090</t>

      <t>struct RECURSIVE_SET_STATUS4res {</t>

      <t>nfsstat4 rssr_status;</t>

      <t>};</t>

      <t>&lt;CODE ENDS&gt;</t>

      <t>DESCRIPTION</t>

      <t>The RECURSIVE_SET_STATUS operation is used by the client to query the
      status of a recursively set task (attributes of a directory and its
      subitems). If the task on the storage server is complete, NFS4_OK is
      returned. If any error occurs during task execution, a response error
      code is returned and the error code is not extended or modified in this
      case so the error code is the same as the error code that may occur
      during the setattr operation. If the current setting task is not
      complete, NFS4_PENDING is returned.</t>

      <t>4.3 Operation TBD3: RECURSIVE_SET_CANCEL &ndash; Canceling a Running
      Task on the Client</t>

      <t>ARGUMENT</t>

      <t>&lt;CODE BEGINS&gt;</t>

      <t>//The following operation is used to cancel the recursive setting
      task that is being executed.</t>

      <t>struct RECURSIVE_SET_CANCEL4args {</t>

      <t>stateid4 rsca_stateid;</t>

      <t>};</t>

      <t>&lt;CODE ENDS&gt;</t>

      <t>RESULT</t>

      <t>&lt;CODE BEGINS&gt;</t>

      <t>struct RECURSIVE_SET_CANCEL4res {</t>

      <t>nfsstat4 rscr_status;</t>

      <t>};</t>

      <t>&lt;CODE ENDS&gt;</t>

      <t>DESCRIPTION</t>

      <t>RECURSIVE_SET_CANCEL is used to cancel the task that is being
      executed. The request packet contains rsca_stateid. The value of
      rsca_stateid is obtained from the response of RECURSIVE_SET. If the
      storage server fails to cancel the task, NFS4ERR_DELAY is returned. When
      receiving the message, the client delays the retry. If the current task
      is complete, NFS4_OK is returned.</t>

      <t>4.4 Operation TBD4: CB_RECURSIVE_SET_NOTIFY &ndash; Notify the
      recursively setting result to client</t>

      <t>ARGUMENT</t>

      <t>&lt;CODE BEGINS&gt;</t>

      <t>struct CB_RECURSIVE_SET_NOTIFY4args {</t>

      <t>nfs_fh4 crsna_fh;</t>

      <t>stateid4 crsna_stateid;</t>

      <t>verifier4 crsna_recursiveverf;</t>

      <t>nfsstat4 crsna_status;</t>

      <t>};</t>

      <t>&lt;CODE ENDS&gt;</t>

      <t>RESULT</t>

      <t>&lt;CODE BEGINS&gt;</t>

      <t>struct CB_RECURSIVE_SET_NOTIFY4res {</t>

      <t>nfsstat4 crsnr_status;</t>

      <t>};</t>

      <t>&lt;CODE ENDS&gt;</t>

      <t>DESCRIPTION</t>

      <t>CB_RECURSIVE_SET_NOTIFY is used to send the server callback to client
      to notify the client of the result of the task of recursively setting
      the attributes of directories and their subitems. Client check the
      crsna_stateid and crsna_recursiveverf and client will finish the wait
      task if they are matched the value received from previous RECURSIVE_SET
      response or will skip the notification in case of not match and return
      NFS4ERR_BAD_STATEID to server.</t>
    </section>

    <section title="Security Considerations">
      <t>TBD</t>
    </section>

    <section title="IANA Considerations">
      <t>TBD</t>
    </section>
  </middle>

  <back>
    <references title="Normative References">
      <?rfc include="reference.RFC.2119"?>

      <?rfc include='reference.RFC.7862'?>
    </references>

    <references title="Informative References">
      <reference anchor="InfRef">
        <front>
          <title/>

          <author>
            <organization/>
          </author>

          <date year="2004"/>
        </front>
      </reference>
    </references>

    <section title="An Appendix">
      <t/>
    </section>
  </back>
</rfc>
