<?xml version="1.0" encoding="US-ASCII"?>
<!DOCTYPE rfc SYSTEM "rfc2629.dtd">
<?xml-stylesheet type='text/xsl' href='rfc2629.xslt' ?>

<?rfc strict="yes" ?>
<?rfc toc="yes"?>
<?rfc tocompact="yes"?>
<?rfc tocdepth="3"?>
<?rfc symrefs="yes"?>
<?rfc sortrefs="yes" ?>
<?rfc compact="yes" ?>
<?rfc subcompact="no" ?>
<?rfc rfcedstyle="yes"?>

<rfc
    category="std"
    obsoletes="3530"
    ipr="pre5378Trust200902"
    number="7530" submissionType="IETF" consensus="yes" >

<front>
    <title abbrev="NFSv4">
      Network File System (NFS) Version 4 Protocol
    </title>

    <author fullname="Thomas Haynes" 
            initials="T." 
            surname="Haynes"
            role="editor">
      <organization abbrev="Primary Data">Primary Data, Inc.</organization>
      <address>
        <postal>
          <street>4300 El Camino Real Ste 100</street>
          <city> Los Altos</city>
          <region>CA</region>
          <code>94022</code>
          <country>United States</country>
        </postal>
        <phone>+1 408 215 1519</phone>
        <email>thomas.haynes@primarydata.com</email>
      </address>
    </author>

    <author initials='D.' surname='Noveck'
            fullname = 'David Noveck'
            role="editor">
      <organization abbrev='Dell'>Dell</organization>
      <address>
        <postal>
          <street>300 Innovative Way</street>
          <city>Nashua</city>
          <region>NH</region>
          <code>03062</code>
          <country>United States</country>
        </postal>
        <phone>+1 781 572 8038</phone>
        <email>dave_noveck@dell.com</email>
      </address>
    </author>

    <date year="2015" month="March"/>

    <abstract>
      <t>
        The Network File System (NFS) version 4 protocol is a
        distributed file system protocol that builds on the heritage
        of NFS protocol version 2 (RFC 1094) and version 3 (RFC 1813).
        Unlike earlier versions, the NFS version 4 protocol supports
        traditional file access while integrating support for file
        locking and the MOUNT protocol.  In addition, support for
        strong security (and its negotiation), COMPOUND operations,
        client caching, and internationalization has been added.  Of
        course, attention has been applied to making NFS version 4
        operate well in an Internet environment.
      </t>
      <t>
        This document, together with the companion External Data
        Representation (XDR) description document, RFC 7531, obsoletes
        RFC 3530 as the definition of the NFS version 4 protocol.
      </t>
    </abstract>

</front>

<middle>

<section anchor="sec:intro" title="Introduction" >

  <section title="Requirements Language">
   <t>The key words &quot;MUST&quot;, &quot;MUST NOT&quot;,
   &quot;REQUIRED&quot;, &quot;SHALL&quot;, &quot;SHALL NOT&quot;,
   &quot;SHOULD&quot;, &quot;SHOULD NOT&quot;, &quot;RECOMMENDED&quot;,
   &quot;MAY&quot;, and &quot;OPTIONAL&quot; in this document are to be
   interpreted as described in <xref target="RFC2119">RFC 2119</xref>,
   except where "REQUIRED" and "RECOMMENDED" are used as qualifiers
   to distinguish classes of attributes as described in Sections
   <xref target='intro_attrs' format="counter" />
   and <xref target='file_attributes' format="counter"/> of this document.
   </t>
  </section>

  <section anchor="v4_goals" title="NFS Version 4 Goals">
    <t>
      The Network File System version 4 (NFSv4) protocol is a further
      revision of the NFS protocol defined already by versions
      2 <xref target="RFC1094" /> and 3 <xref target="RFC1813" />.
      It retains the essential
      characteristics of previous versions: design for easy recovery;
      independent of transport protocols, operating systems, and
      file systems; simplicity; and good performance.  The NFSv4
      revision has the following goals:

      <list style='symbols'>
        <t>
          Improved access and good performance on the Internet.
        <vspace blankLines='1' />
          The protocol is designed to transit firewalls easily,
          perform well where latency is high and bandwidth is low,
          and scale to very large numbers of clients per server.
        </t>

        <t>
          Strong security with negotiation built into the protocol.
        <vspace blankLines='1' />
          The protocol builds on the work of the Open Network Computing
          (ONC) Remote Procedure Call (RPC) working group
          in supporting the RPCSEC_GSS protocol (see both <xref target="RFC2203" />
          and <xref target="RFC5403" />).  Additionally, the NFSv4 protocol
          provides a mechanism to allow clients and
          servers the ability to negotiate security and require clients
          and servers to support a minimal set of security schemes.
        </t>

        <t>
          Good cross-platform interoperability.
        <vspace blankLines='1' />
          The protocol features a file system model that provides a
          useful, common set of features that does not unduly favor
          one file system or operating system over another.
        </t>

        <t>
          Designed for protocol extensions.
        <vspace blankLines='1' />
          The protocol is designed to accept standard extensions that
          do not compromise backward compatibility.
        </t>
      </list>
    </t>

    <t>
      This document, together with the companion External Data                
      Representation (XDR) description document <xref target="RFC7531" />,
      obsoletes <xref target="RFC3530" /> as the authoritative document
      describing NFSv4.  It does not introduce any over-the-wire protocol
      changes, in the sense that previously valid requests remain valid.
    </t>
  </section>

  <section anchor="document_incons"
      title="Definitions in the Companion Document RFC 7531 Are Authoritative">
    <t>
      The "Network File System (NFS) Version 4
      External Data Representation Standard (XDR) Description" <xref
      target="RFC7531" /> contains
      the definitions in XDR description language of the constructs
      used by the protocol.  Inside this document, several
      of the constructs are reproduced for purposes of explanation.  The
      reader is warned of the possibility of errors in the reproduced
      constructs outside of <xref target="RFC7531" />.
      For any part of the document that is inconsistent with
      <xref target="RFC7531" />, <xref target="RFC7531" /> is to be
      considered authoritative.
    </t>
  </section>

  <section anchor="feature_overview" title="Overview of NFSv4 Features">
    <t>
      To provide a reasonable context for the reader, the major
      features of the NFSv4 protocol will be reviewed in brief.
      This is done to provide an appropriate context for both
      the reader who is familiar with the previous versions of the
      NFS protocol and the reader who is new to the NFS protocols.
      For the reader new to the NFS protocols, some fundamental
      knowledge is still expected.  The reader should
      be familiar with the XDR and RPC protocols as described in
      <xref target="RFC4506" /> and <xref target="RFC5531" />.
      A basic knowledge of file systems and distributed file systems
      is expected as well.
    </t>

    <section anchor="intro_rpc" title="RPC and Security">

      <t>
        As with previous versions of NFS, the XDR and RPC
        mechanisms used for the NFSv4 protocol are those
        defined in <xref target="RFC4506" /> and
        <xref target="RFC5531" />.  To meet end-to-end
        security requirements, the RPCSEC_GSS framework
        (both version 1 in <xref target="RFC2203" /> and
        version 2 in <xref target="RFC5403" />)
        will be used to extend the basic RPC security.  With the
        use of RPCSEC_GSS, various mechanisms can be provided to
        offer authentication, integrity, and privacy to the
        NFSv4 protocol.  Kerberos V5 will be used as described
        in <xref target="RFC4121" /> to provide one security
        framework.  With the use of RPCSEC_GSS, other mechanisms
        may also be specified and used for NFSv4 security.
      </t>

      <t>
        To enable in-band security negotiation, the NFSv4
        protocol has added a new operation that provides the client
        with a method of querying the server about its policies regarding
        which security mechanisms must be used for access to the
        server's file system resources.  With this, the client can
        securely match the security mechanism that meets the policies
        specified at both the client and server.
      </t>
    </section>

    <section anchor="intro_procs" title="Procedure and Operation Structure">

      <t>
        A significant departure from the previous versions of the
        NFS protocol is the introduction of the COMPOUND procedure.
        For the NFSv4 protocol, there are two RPC procedures:
        NULL and COMPOUND.  The COMPOUND procedure is defined in
        terms of operations, and these operations correspond more
        closely to the traditional NFS procedures.
      </t>

      <t>
        With the use of the COMPOUND procedure, the client is able
        to build simple or complex requests.  These COMPOUND requests
        allow for a reduction in the number of RPCs needed for logical
        file system operations.  For example, without previous contact
        with a server a client will be able to read data from a file
        in one request by combining LOOKUP, OPEN, and READ operations
        in a single COMPOUND RPC.  With previous versions of the NFS
        protocol, this type of single request was not possible.
      </t>

      <t>
        The model used for COMPOUND is very simple.  There is no
        logical OR or ANDing of operations.  The operations combined
        within a COMPOUND request are evaluated in order by the server.
        Once an operation returns a failing result, the evaluation
        ends and the results of all evaluated operations are returned
        to the client.
      </t>

      <t>
        The NFSv4 protocol continues to have the client refer
        to a file or directory at the server by a "filehandle".  The
        COMPOUND procedure has a method of passing a filehandle from
        one operation to another within the sequence of operations.
        There is a concept of a current filehandle and a
        saved filehandle.  Most operations use the current filehandle
        as the file system object to operate upon.  The
        saved filehandle is used as temporary filehandle storage within
        a COMPOUND procedure as well as an additional operand for
        certain operations.
      </t>
    </section>

    <section anchor="intro_fs_model" title="File System Model">
      <t>
        The general file system model used for the NFSv4
        protocol is the same as previous versions.  The server
        file system is hierarchical, with the regular files contained
        within being treated as opaque byte streams.  In a slight
        departure, file and directory names are encoded with UTF-8
        to deal with the basics of internationalization.
      </t>

      <t>
        The NFSv4 protocol does not require a separate
        protocol to provide for the initial mapping between pathname
        and filehandle.  Instead of using the older MOUNT protocol
        for this mapping, the server provides a root filehandle
        that represents the logical root or top of the file system
        tree provided by the server.  The server provides multiple
        file systems by gluing them together with pseudo-file systems.
        These pseudo-file systems provide for potential gaps in the
        pathnames between real file systems.
      </t>

      <section anchor="intro_fh_types" title="Filehandle Types">
        <t>
          In previous versions of the NFS protocol, the filehandle
          provided by the server was guaranteed to be valid or
          persistent for the lifetime of the file system object
          to which it referred.  For some server implementations,
          this persistence requirement has been difficult to meet.
          For the NFSv4 protocol, this requirement has been
          relaxed by introducing another type of filehandle -- volatile.
          With persistent and volatile filehandle types, the server
          implementation can match the abilities of the file system at
          the server along with the operating environment.  The client
          will have knowledge of the type of filehandle being provided
          by the server and can be prepared to deal with the semantics
          of each.
        </t>
      </section>

      <section anchor="intro_attrs" title="Attribute Types">
        <t>
          The NFSv4 protocol has a rich and extensible
          file object attribute structure, which is divided
          into REQUIRED, RECOMMENDED, and named attributes
          (see <xref target="file_attributes"/>).
        </t>
        <t>
          Several (but not all) of the REQUIRED attributes
          are derived from the attributes of NFSv3 (see the
          definition of the fattr3 data type in <xref
          target="RFC1813"/>). An example of a REQUIRED
          attribute is the file object's type (<xref
          target="attrdef_type"/>) so that regular files
          can be distinguished from directories (also known
          as folders in some operating environments) and
          other types of objects. REQUIRED attributes are
          discussed in <xref target="mandatory_attributes_intro"/>.
        </t>
        <t>
          An example of the RECOMMENDED attributes is
          an acl (<xref target="attrdef_acl" />).  This attribute defines
          an Access Control List (ACL) on a file object. An ACL provides
          file access control beyond the
          model used in NFSv3.   The ACL definition allows
          for specification of specific sets of permissions
          for individual users and groups.  In addition,
          ACL inheritance allows propagation of access
          permissions and restriction down a directory tree
          as file system objects are created.  RECOMMENDED
          attributes are discussed in <xref
          target="recommended_attributes_intro"/>.
        </t>
        <t>
          A named attribute is an opaque byte stream that is associated
          with a directory or file and referred to by a string name.
          Named attributes are meant to be used by client applications
          as a method to associate application-specific data with a
          regular file or directory.  NFSv4.1 modifies named attributes
          relative to NFSv4.0 by tightening the allowed operations in
          order to prevent the development of non&nbhy;interoperable
          implementations.  Named attributes are discussed
          in <xref target="named_attributes_intro" />.
        </t>
      </section>
      <section anchor="intro_ms_namespace" title="Multi-Server Namespace">
        <t>
          A single-server namespace is the file system hierarchy that
          the server presents for remote access. It is a proper
          subset of all the file systems available locally.
          NFSv4 contains a number of features to allow
          implementation of namespaces that cross server boundaries
          and that allow and facilitate a non-disruptive transfer of
          support for individual file systems between servers.  They
          are all based upon attributes that allow one file system to
          specify alternative or new locations for that file system.
          That is, just as a client might traverse across local
          file systems on a single server, it can now traverse to a remote
          file system on a different server.
        </t>
        <t>
          These attributes may be used together with the concept
          of absent file systems, which provide specifications
          for additional locations but no actual file system
          content.  This allows a number of important facilities:
          <list style="symbols">
            <t>
              Location attributes may be used with absent file systems
              to implement referrals whereby one server may direct the
              client to a file system provided by another server.  This
              allows extensive multi-server namespaces to be constructed.
            </t>
            <t>
              Location attributes may be provided for present file systems
              to provide the locations of alternative file system instances
              or replicas to be used in the event that the current
              file system instance becomes unavailable.
            </t>
            <t>
              Location attributes may be provided when a previously
              present file system becomes absent.  This allows
              non-disruptive migration of file systems to alternative
              servers.
            </t>
          </list>
        </t>
      </section>
    </section>

    <section anchor="intro_open_op" title="OPEN and CLOSE">

      <t>
        The NFSv4 protocol introduces OPEN and CLOSE
        operations.  The OPEN operation provides a single point where
        file lookup, creation, and share semantics (see
        <xref target='ss:fl:share_res' />) can be combined.
        The CLOSE operation also provides for the release of state
        accumulated by OPEN.
      </t>
    </section>

    <section anchor="intro_locking" title="File Locking">

      <t>
        With the NFSv4 protocol, the support for byte-range
        file locking is part of the NFS protocol.  The file locking
        support is structured so that an RPC callback mechanism is
        not required.  This is a departure from the previous versions
        of the NFS file locking protocol, Network Lock Manager (NLM) <xref target="RFC1813" />.
        The state associated with file locks is maintained at the
        server under a lease-based model.  The server defines a single
        lease period for all state held by an NFS client.  If the
        client does not renew its lease within the defined period,
        all state associated with the client's lease may be released
        by the server.  The client may renew its lease by use of
        the RENEW operation or implicitly by use of other operations
        (primarily READ).
      </t>
    </section>

    <section anchor="intro_delegs" title="Client Caching and Delegation">

      <t>
        The file, attribute, and directory caching for the NFSv4
        protocol is similar to previous versions.  Attributes and
        directory information are cached for a duration determined by
        the client.  At the end of a predefined timeout, the client
        will query the server to see if the related file system object
        has been updated.
      </t>

      <t>
        For file data, the client checks its cache validity when the
        file is opened.  A query is sent to the server to determine
        if the file has been changed.  Based on this information,
        the client determines if the data cache for the file should be
        kept or released.  Also, when the file is closed, any modified
        data is written to the server.
      </t>

      <t>
        If an application wants to serialize access to file data, file
        locking of the file data ranges in question should be used.
      </t>

      <t>
        The major addition to NFSv4 in the area of caching is the
        ability of the server to delegate certain responsibilities
        to the client.  When the server grants a delegation for a
        file to a client, the client is guaranteed certain semantics
        with respect to the sharing of that file with other clients.
        At OPEN, the server may provide the client either a read
        (OPEN_DELEGATE_READ) or a write (OPEN_DELEGATE_WRITE)
        delegation for the file (see <xref target='ss:cc:open_dele' />).
        If the client is granted an OPEN_DELEGATE_READ delegation,
        it is assured that no other client has the ability to write
        to the file for the duration of the delegation.  If the
        client is granted an OPEN_DELEGATE_WRITE delegation, the
        client is assured that no other client has read or write
        access to the file.
      </t>

      <t>
        Delegations can be recalled by the server.  If another
        client requests access to the file in such a way that the
        access conflicts with the granted delegation, the server is
        able to notify the initial client and recall the delegation.
        This requires that a callback path exist between the server and
        client.  If this callback path does not exist, then delegations
        cannot be granted.  The essence of a delegation is that it
        allows the client to locally service operations such as OPEN,
        CLOSE, LOCK, LOCKU, READ, or WRITE without immediate interaction
        with the server.
      </t>
    </section>
  </section>

  <section anchor="intro_gen_defs" title="General Definitions">

    <t>
      The following definitions are provided for the purpose of providing
      an appropriate context for the reader.

      <list style='hanging'>
        <t hangText="Absent File System:">
          A file system is "absent" when a namespace component does not have a 
          backing file system.
        </t>
        <t hangText="Anonymous Stateid:">
          The Anonymous Stateid is a special locking object and is
          defined in <xref target="ss:fl:special" />.
        </t>
        <t hangText="Byte:">
          In this document, a byte is an octet, i.e., a datum exactly
          8&nbsp;bits in length.
        </t>
        <t hangText="Client:" anchor="client_def">
          The client is the entity that accesses the NFS server's
          resources.  The client may be an application that contains
          the logic to access the NFS server directly.  The client
          may also be the traditional operating system client that
          provides remote file system services for a set of applications.
        <vspace blankLines='1' />
          With reference to byte-range locking, the client is also the
          entity that maintains a set of locks on behalf of one or more
          applications.  This client is responsible for crash or failure
          recovery for those locks it manages.
        <vspace blankLines='1' />
          Note that multiple clients may share the same transport and
          connection, and multiple clients may exist on the same network
          node.
        </t>

        <t hangText="Client ID:">
          The client ID is a 64-bit quantity used as a unique, shorthand
          reference to a client-supplied verifier and ID.  The server
          is responsible for supplying the client ID.
        </t>

        <t hangText="File System:">
          The file system is the collection of objects on a server that
          share the same fsid attribute (see <xref target="attrdef_fsid"/>).
        </t>

        <t hangText="Lease:">
          A lease is an interval of time defined by the server for which
          the client is irrevocably granted a lock.  At the end of a
          lease period the lock may be revoked if the lease has not
          been extended.  The lock must be revoked if a conflicting
          lock has been granted after the lease interval.
        <vspace blankLines='1' />
          All leases granted by a server have the same fixed
          duration.  Note that the fixed interval duration was chosen to
          alleviate the expense a server would have in maintaining
          state about variable-length leases across server failures.
        </t>

        <t hangText="Lock:">
          The term "lock" is used to refer to record (byte-range)
          locks as well as share reservations unless specifically
          stated otherwise.
        </t>

        <t hangText="Lock-Owner:">
          Each byte-range lock is associated with a specific lock-owner
          and an open-owner.  The lock-owner consists of a
          client ID and an opaque owner string.
          The client presents this to the server to establish
          the ownership of the byte-range lock as needed.
        </t>

        <t hangText="Open-Owner:">
          Each open file is associated with a specific open-owner,
          which consists of a client ID and an opaque owner string.
          The client presents this to the server to establish
          the ownership of the open as needed.
        </t>

        <t hangText="READ Bypass Stateid:">
          The READ Bypass Stateid is a special locking object and is
          defined in <xref target="ss:fl:special" />.
        </t>

        <t hangText="Server:">
          The "server" is the entity responsible for coordinating
          client access to a set of file systems.
        </t>

        <t hangText="Stable Storage:">
          NFSv4 servers must be able to recover without data
          loss from multiple power failures (including cascading
          power failures, that is, several power failures in quick
          succession), operating system failures, and hardware failure
          of components other than the storage medium itself (for
          example, disk, non&nbhy;volatile RAM).
        <vspace blankLines='1' />
          Some examples of stable storage that are allowable for an
          NFS server include:

          <list style='format (%d)'>
            <t>
              Media commit of data.  That is, the modified data
              has been successfully written to the disk media --
              for example, the disk platter.
            </t>

            <t>
              An immediate reply disk drive with battery-backed
              on-drive intermediate storage or uninterruptible
              power system (UPS).
            </t>

            <t>
              Server commit of data with battery-backed intermediate
              storage and recovery software.
            </t>

            <t>
              Cache commit with UPS and recovery software.
            </t>
          </list>
        </t>

        <t hangText="Stateid:">
          A stateid is a 128-bit quantity returned by a server that
          uniquely identifies the open and locking states provided by the
          server for a specific open-owner or lock-owner/open-owner pair for
          a specific file and type of lock.
        </t>

        <t hangText="Verifier:">
          A verifier is a 64-bit quantity generated by the client that
          the server can use to determine if the client has restarted and lost
          all previous lock state.
        </t>
      </list>
    </t>
  </section>

  <section anchor="changes_since3530" title="Changes since RFC 3530">
    <t>
      The main changes from RFC 3530 <xref target="RFC3530" /> are:

      <list style='symbols'>
        <t>
          The XDR definition has been moved to a companion document
          <xref target="RFC7531" />.
        </t>
        <t>
          The IETF intellectual property statements were updated to the
          latest version.
        </t>
        <t>
          There is a restructured and more complete explanation of
          multi-server namespace features.
        </t>
        <t>
          The handling of domain names was updated to reflect
          Internationalized Domain Names in Applications (IDNA)
          <xref target='RFC5891' />.
        </t>
        <t>
          The previously required LIPKEY and SPKM-3 security mechanisms
          have been removed.
        </t>
        <t>
          Some clarification was provided regarding a client
          re-establishing callback information to the new server
          if state has been migrated.
        </t>
        <t>
          A third edge case was added for courtesy locks and network
          partitions.
        </t>
        <t>
          The definition of stateid was strengthened.
        </t>
      </list>
    </t>
  </section>

  <section anchor="changes_since3010" title="Changes between RFC 3010 and RFC 3530">
    <t>
      The definition of the NFSv4 protocol in <xref target="RFC3530" />
      replaced and obsoleted the definition present in
      <xref target="RFC3010" />.  While portions of the two documents
      remained the same, there were substantive changes in others.
      The changes made between <xref target="RFC3010" /> and
      <xref target="RFC3530" /> reflect implementation experience and
      further review of the protocol.
    </t>

    <t>
      The following list is not inclusive of all changes but
      presents some of the most notable changes or additions made:

      <list style='symbols'>
        <t>
          The state model has added an open_owner4 identifier.  This
          was done to accommodate POSIX-based clients and the model
          they use for file locking.  For POSIX clients, an open_owner4
          would correspond to a file descriptor potentially shared
          amongst a set of processes and the lock_owner4 identifier
          would correspond to a process that is locking a file.
        </t>

        <t>
          Added clarifications and error conditions for the
          handling of the owner and group attributes.  Since these
          attributes are string based (as opposed to the numeric
          uid/gid of previous versions of NFS), translations may not
          be available and hence the changes made.
        </t>

        <t>
          Added clarifications for the ACL and mode attributes to
          address evaluation and partial support.
        </t>

        <t>
          For identifiers that are defined as XDR opaque, set limits
          on their size.
        </t>

        <t>
          Added the mounted_on_fileid attribute to allow POSIX clients
          to correctly construct local mounts.
        </t>

        <t>
          Modified the SETCLIENTID/SETCLIENTID_CONFIRM operations to
          deal correctly with confirmation details along with adding
          the ability to specify new client callback information.
          Also added clarification of the callback information itself.
        </t>

        <t>
          Added a new operation RELEASE_LOCKOWNER to enable notifying
          the server that a lock_owner4 will no longer be used by
          the client.
        </t>

        <t>
          Added RENEW operation changes to identify the client correctly
          and allow for additional error returns.
        </t>

        <t>
          Verified error return possibilities for all operations.
        </t>

        <t>
          Removed use of the pathname4 data type from LOOKUP and OPEN
          in favor of having the client construct a sequence of LOOKUP
          operations to achieve the same effect.
        </t>
      </list>
    </t>
  </section>

</section>

<section anchor="sec:data_types" title="Protocol Data Types">

   <t>
     The syntax and semantics to describe the data types of the
     NFSv4 protocol are defined in the XDR <xref target="RFC4506" />
     and RPC <xref target="RFC5531" /> documents.  The next sections
     build upon the XDR data types to define types and structures
     specific to this protocol. As a reminder, the size constants and
     authoritative definitions can be found in <xref target="RFC7531" />.
   </t>

  <section anchor="basic_types" title="Basic Data Types">

  <t><xref target="basic_data_types"/> lists the base NFSv4 data types.</t>

  <?rfc compact="no"?>
    <texttable anchor='basic_data_types' title="Base NFSv4 Data Types">
      <ttcol align='left'>Data Type</ttcol>
      <ttcol align='left'>Definition</ttcol>
        <c>int32_t</c>                <c>typedef int int32_t;</c>

        <c>uint32_t</c>                <c>typedef unsigned int uint32_t;</c>

        <c>int64_t</c>                <c>typedef hyper int64_t;</c>

        <c>uint64_t</c>                <c>typedef unsigned hyper uint64_t;</c>

        <c>attrlist4</c>                <c>typedef opaque attrlist4&lt;>;</c>
        <c/>        <c>Used for file/directory attributes.</c>

        <c>bitmap4</c>                <c>typedef uint32_t bitmap4&lt;>;</c>
        <c/>        <c>Used in attribute array encoding.</c>

        <c>changeid4</c>                <c>typedef uint64_t changeid4;</c>
        <c/>        <c>Used in the definition of change_info4.</c>

        <c>clientid4</c>                <c>typedef uint64_t clientid4;</c>
        <c/>        <c>Shorthand reference to client identification.</c>

        <c>count4</c>                <c>typedef uint32_t count4;</c>
        <c/>        <c>Various count parameters (READ, WRITE, COMMIT).</c>

        <c>length4</c>                <c>typedef uint64_t length4;</c>
        <c/>        <c>Describes LOCK lengths.</c>

        <c>mode4</c>                <c>typedef uint32_t mode4;</c>
        <c/>        <c>Mode attribute data type.</c>

        <c>nfs_cookie4</c>                <c>typedef uint64_t nfs_cookie4;</c>
        <c/>        <c>Opaque cookie value for READDIR.</c>

        <c>nfs_fh4</c>                <c>typedef opaque nfs_fh4&lt;NFS4_FHSIZE>;</c>
        <c/>        <c>Filehandle definition.</c>

        <c>nfs_ftype4</c>                <c>enum nfs_ftype4;</c>
        <c/>        <c>Various defined file types.</c>

        <c>nfsstat4</c>                <c>enum nfsstat4;</c>
        <c/>        <c>Return value for operations.</c>

        <c>nfs_lease4</c>                <c>typedef uint32_t nfs_lease4;</c>
        <c/>        <c>Duration of a lease in seconds.</c>

        <c>offset4</c>                <c>typedef uint64_t offset4;</c>
        <c/>        <c>Various offset designations (READ, WRITE, LOCK, COMMIT).</c>

        <c>qop4</c>                <c>typedef uint32_t qop4;</c>
        <c/>        <c>Quality of protection designation in SECINFO.</c>

        <c>sec_oid4</c>                <c>typedef opaque sec_oid4&lt;>;</c>
        <c/>        <c>Security Object Identifier.  The sec_oid4 data type is
not really opaque.  Instead, it contains an ASN.1 OBJECT IDENTIFIER as used by
GSS-API in the mech_type argument to GSS_Init_sec_context.  See <xref target="RFC2743" /> for details.</c>

        <c>seqid4</c>                <c>typedef uint32_t seqid4;</c>
        <c/>        <c>Sequence identifier used for file locking.</c>

        <c>utf8string</c>                <c>typedef opaque utf8string&lt;>;</c>
        <c/>        <c>UTF-8 encoding for strings.</c>

        <c>utf8str_cis</c>                <c>typedef utf8string utf8str_cis;</c>
        <c/>        <c>Case-insensitive UTF-8 string.</c>

        <c>utf8str_cs</c>                <c>typedef utf8string utf8str_cs;</c>
        <c/>        <c>Case-sensitive UTF-8 string.</c>

        <c>utf8str_mixed</c>                <c>typedef utf8string utf8str_mixed;</c>
        <c/>        <c>UTF-8 strings with a case-sensitive prefix and a case-insensitive suffix.</c>

        <c>component4</c>                <c>typedef utf8str_cs component4;</c>
        <c/>        <c>Represents pathname components.</c>

        <c>linktext4</c>                <c>typedef opaque linktext4&lt;>;</c>
        <c/>        <c>Symbolic link contents ("symbolic link" is defined in an Open Group <xref target='openg_symlink' /> standard).</c>

        <c>ascii_REQUIRED4</c>                <c>typedef utf8string ascii_REQUIRED4;</c>
        <c/>        <c>String is sent as ASCII and thus is automatically UTF-8.</c>

        <c>pathname4</c>                <c>typedef component4 pathname4&lt;>;</c>
        <c/>        <c>Represents pathname for fs_locations.</c>

        <c>nfs_lockid4</c>                <c>typedef uint64_t nfs_lockid4;</c>

        <c>verifier4</c>                <c>typedef opaque verifier4[NFS4_VERIFIER_SIZE];</c>
        <c/>        <c>Verifier used for various operations (COMMIT, CREATE, OPEN, READDIR, WRITE) NFS4_VERIFIER_SIZE is defined as 8.</c>
    </texttable>
  <?rfc compact="yes"?>
  </section>

  <section anchor="sec:sdts" title="Structured Data Types">

    <section toc="exclude" anchor="nfstime4" title="nfstime4">
<figure>
 <artwork>
struct nfstime4 {
        int64_t         seconds;
        uint32_t        nseconds;
};
 </artwork>
</figure>

      <t>
        The nfstime4 structure gives the number of seconds and
        nanoseconds since midnight or 0 hour January 1, 1970 Coordinated
        Universal Time (UTC).  Values greater than zero for the seconds
        field denote dates after the 0 hour January 1, 1970.  Values less
        than zero for the seconds field denote dates before the 0 hour
        January 1, 1970.  In both cases, the nseconds field is to be
        added to the seconds field for the final time representation.
        For example, if the time to be represented is one-half second
        before 0 hour January 1, 1970, the seconds field would have a
        value of negative one (-1) and the nseconds fields would have
        a value of one-half second (500000000).  Values greater than
        999,999,999 for nseconds are considered invalid.
      </t>

      <t>
        This data type is used to pass time and date information.
        A server converts to and from its local representation of
        time when processing time values, preserving as much accuracy
        as possible.  If the precision of timestamps stored for a
        file system object is less than defined, loss of precision can
        occur.  An adjunct time maintenance protocol is recommended to
        reduce client and server time skew.
      </t>
    </section>

    <section toc="exclude" anchor="time_how4" title="time_how4">
<figure>
 <artwork>
enum time_how4 {
        SET_TO_SERVER_TIME4 = 0,
        SET_TO_CLIENT_TIME4 = 1
};
 </artwork>
</figure>
    </section>

    <section toc="exclude" anchor="settime4" title="settime4">
<figure>
 <artwork>
union settime4 switch (time_how4 set_it) {
 case SET_TO_CLIENT_TIME4:
         nfstime4       time;
 default:
         void;
};
 </artwork>
</figure>

      <t>
        The above definitions are used as the attribute definitions to
        set time values.  If set_it is SET_TO_SERVER_TIME4, then the
        server uses its local representation of time for the time value.
      </t>
    </section>

    <section toc="exclude" anchor="specdata4" title="specdata4">

<figure>
 <artwork>
struct specdata4 {
        uint32_t specdata1; /* major device number */
        uint32_t specdata2; /* minor device number */
};
 </artwork>
</figure>
      <t>
        This data type represents additional information for the device
        file types NF4CHR and NF4BLK.
      </t>
    </section>

    <section toc="exclude" anchor="fsid4" title="fsid4">
<figure>
 <artwork>
struct fsid4 {
        uint64_t        major;
        uint64_t        minor;
};
 </artwork>
</figure>
      <t>
        This type is the file system identifier that is used as a
        REQUIRED attribute.
      </t>
    </section>

    <section toc="exclude" anchor="fs_location4" title="fs_location4">
<figure>
 <artwork>
struct fs_location4 {
        utf8str_cis             server&lt;>;
        pathname4               rootpath;
};
 </artwork>
</figure>
    </section>

    <section toc="exclude" anchor="fs_locations4" title="fs_locations4">
<figure>
 <artwork>
struct fs_locations4 {
        pathname4       fs_root;
        fs_location4    locations&lt;>;
};
 </artwork>
</figure>
      <t>
        The fs_location4 and fs_locations4 data types are used for the
        fs_locations RECOMMENDED attribute, which is used for migration
        and replication support.
      </t>
    </section>

    <section toc="exclude" anchor="fattr4" title="fattr4">
<figure>
 <artwork>
struct fattr4 {
        bitmap4         attrmask;
        attrlist4       attr_vals;
};
 </artwork>
</figure>

      <t>
        The fattr4 structure is used to represent file and directory
        attributes.
      </t>

      <t>
        The bitmap is a counted array of 32-bit integers used to
        contain bit values.  The position of the integer in the array
        that contains bit n can be computed from the expression
        (n / 32), and its bit within that integer is (n mod 32).
      </t>

      <t>
        <figure>
          <artwork>
                    0            1
  +-----------+-----------+-----------+--
  |  count    | 31  ..  0 | 63  .. 32 |
  +-----------+-----------+-----------+--
          </artwork>
        </figure>
      </t>
    </section>

    <section toc="exclude" anchor="change_info4" title="change_info4">
<figure>
 <artwork>
struct change_info4 {
        bool            atomic;
        changeid4       before;
        changeid4       after;
};
 </artwork>
</figure>
      <t>
        This structure is used with the CREATE, LINK, REMOVE, and RENAME
        operations to let the client know the value of the change
        attribute for the directory in which the target file system
        object resides.
      </t>
    </section>


    <section toc="exclude" anchor="clientaddr4" title="clientaddr4">
<figure>
 <artwork>
struct clientaddr4 {
        /* see struct rpcb in RFC 1833 */
        string r_netid&lt;>;    /* network id */
        string r_addr&lt;>;     /* universal address */
};
 </artwork>
</figure>
      <t>
        The clientaddr4 structure is used as part of the SETCLIENTID
        operation, either (1) to specify the address of the client that is
        using a client ID or (2) as part of the callback registration.
        The r_netid and r_addr fields respectively contain a network
        id and universal address.  The network id and universal
        address concepts, together with formats for TCP over IPv4
        and TCP over IPv6, are defined in <xref target="RFC5665" />,
        specifically Tables 2 and 3 and Sections&nbsp;5.2.3.3 and 5.2.3.4.
      </t>
    </section>

    <section toc="exclude" anchor="cb_client4" title="cb_client4">
<figure>
 <artwork>
struct cb_client4 {
        unsigned int    cb_program;
        clientaddr4     cb_location;
};
 </artwork>
</figure>
      <t>
        This structure is used by the client to inform the server of
        its callback address; it includes the program number and client
        address.
      </t>
    </section>

    <section toc="exclude" anchor="nfs_client_id4" title="nfs_client_id4">
<figure>
 <artwork>
struct nfs_client_id4 {
        verifier4       verifier;
        opaque          id&lt;NFS4_OPAQUE_LIMIT>;
};
 </artwork>
</figure>
      <t>
        This structure is part of the arguments to the SETCLIENTID
        operation.
      </t>
    </section>

    <section toc="exclude" anchor="open_owner4" title="open_owner4">
<figure>
 <artwork>
struct open_owner4 {
        clientid4       clientid;
        opaque          owner&lt;NFS4_OPAQUE_LIMIT>;
};
 </artwork>
</figure>
      <t>
        This structure is used to identify the owner of open state.
      </t>
    </section>

    <section toc="exclude" anchor="lock_owner4" title="lock_owner4">
<figure>
 <artwork>
struct lock_owner4 {
        clientid4       clientid;
        opaque          owner&lt;NFS4_OPAQUE_LIMIT>;
};
 </artwork>
</figure>
      <t>
        This structure is used to identify the owner of file locking
        state.
      </t>
    </section>

    <section toc="exclude" anchor="open_to_lock_owner4" title="open_to_lock_owner4">
<figure>
 <artwork>
struct open_to_lock_owner4 {
        seqid4          open_seqid;
        stateid4        open_stateid;
        seqid4          lock_seqid;
        lock_owner4     lock_owner;
};
 </artwork>
</figure>
      <t>
        This structure is used for the first LOCK operation done for an
        open_owner4.  It provides both the open_stateid and lock_owner
        such that the transition is made from a valid open_stateid
        sequence to that of the new lock_stateid sequence.  Using this
        mechanism avoids the confirmation of the lock_owner/lock_seqid
        pair since it is tied to established state in the form of the
        open_stateid/open_seqid.
      </t>
    </section>

    <section toc="exclude" anchor="stateid4" title="stateid4">
<figure>
 <artwork>
struct stateid4 {
        uint32_t        seqid;
        opaque          other[NFS4_OTHER_SIZE];
};
 </artwork>
</figure>
      <t>
        This structure is used for the various state-sharing mechanisms
        between the client and server.  For the client, this data
        structure is read-only.  The server is required to increment the
        seqid field monotonically at each transition of the stateid.
        This is important since the client will inspect the seqid in
        OPEN stateids to determine the order of OPEN processing done
        by the server.
      </t>
    </section>

  </section>
</section>

<section anchor="sec:rpc_flavors" title="RPC and Security Flavor">

  <t>
    The NFSv4 protocol is an RPC application that uses RPC version 2
    and the XDR as defined in <xref target="RFC5531" />
    and <xref target="RFC4506" />.  The RPCSEC_GSS security flavors as
    defined in version 1 (<xref target="RFC2203" />) and version 2
    (<xref target="RFC5403" />) MUST be implemented
    as the mechanism to deliver stronger security for the NFSv4
    protocol.  However, deployment of RPCSEC_GSS is optional.
  </t>

  <section title="Ports and Transports">

    <t>
      Historically, NFSv2 and NFSv3 servers have resided on
      port 2049.  The registered port 2049 <xref target="RFC3232" /> for the NFS protocol
      SHOULD be the default configuration.  Using the registered port
      for NFS services means the NFS client will not need to use the RPC
      binding protocols as described in <xref target="RFC1833" />; this
      will allow NFS to transit firewalls.
    </t>

    <t>
      Where an NFSv4 implementation supports operation over the IP network
      protocol, the supported transport layer between NFS and IP MUST be an IETF
      standardized transport protocol that is specified to avoid network
      congestion; such  transports include TCP and the
      Stream Control Transmission Protocol (SCTP).  To enhance the
      possibilities for interoperability, an NFSv4 implementation MUST
      support operation over the TCP transport protocol.
    </t>

    <t>
      If TCP is used as the transport, the client and server SHOULD use
      persistent connections.  This will prevent the weakening of TCP's
      congestion control via short-lived connections and will improve
      performance for the Wide Area Network (WAN) environment by
      eliminating the need for SYN handshakes.
    </t>

    <t>
      As noted in <xref target="sec:security" />,
      the authentication model for NFSv4 has moved from
      machine-based to principal-based.  However, this modification
      of the authentication model does not
      imply a technical requirement to move the TCP connection management
      model from whole machine-based to one based on a per-user model.
      In particular, NFS over TCP client implementations have traditionally
      multiplexed traffic for multiple users over a common TCP connection
      between an NFS client and server.  This has been true, regardless of
      whether the NFS client is using AUTH_SYS, AUTH_DH, RPCSEC_GSS, or
      any other flavor.  Similarly, NFS over TCP server implementations
      have assumed such a model and thus scale the implementation of TCP
      connection management in proportion to the number of expected client
      machines.  It is intended that NFSv4 will not modify this
      connection management model.  NFSv4 clients that violate
      this assumption can expect scaling issues on the server and hence
      reduced service.
    </t>

    <section title="Client Retransmission Behavior">
      <t>
        When processing an NFSv4 request received over a reliable transport such as
        TCP, the NFSv4 server MUST NOT silently drop the request,
        except if the established transport connection has been broken.  Given such a
        contract between NFSv4 clients and servers, clients MUST NOT
        retry a request unless one or both of the following are true:

        <list style='symbols'>
          <t>
            The transport connection has been broken
          </t>

          <t>
            The procedure being retried is the NULL procedure
          </t>
        </list>
      </t>

      <t>
        Since reliable transports, such as TCP, do not always synchronously
        inform a peer when the other peer has broken the connection (for
        example, when an NFS server reboots), the NFSv4 client may
        want to actively "probe" the connection to see if has been broken.
        Use of the NULL procedure is one recommended way to do so.  So, when
        a client experiences a remote procedure call timeout (of some
        arbitrary implementation-specific amount), rather than retrying the
        remote procedure call, it could instead issue a NULL procedure call
        to the server.  If the server has died, the transport connection
        break will eventually be indicated to the NFSv4 client.
        The client can then reconnect, and then retry the original request.
        If the NULL procedure call gets a response, the connection has
        not broken.  The client can decide to wait longer for the original
        request's response, or it can break the transport connection and
        reconnect before re&nbhy;sending the original request.
      </t>

      <t>
        For callbacks from the server to the client, the same rules apply,
        but the server doing the callback becomes the client, and the client
        receiving the callback becomes the server.
      </t>
    </section>
  </section>

  <section title="Security Flavors">

    <t>
      Traditional RPC implementations have included AUTH_NONE, AUTH_SYS,
      AUTH_DH, and AUTH_KRB4 as security flavors.  With
      <xref target="RFC2203" />, an additional security flavor of RPCSEC_GSS
      has been introduced, which uses the functionality of GSS-API
      <xref target="RFC2743" />.  This allows for the
      use of various security mechanisms by the RPC layer without the
      additional implementation overhead of adding RPC security flavors.
      For NFSv4, the RPCSEC_GSS security flavor MUST be used to
      enable the mandatory-to-implement security mechanism.  Other flavors,
      such as AUTH_NONE, AUTH_SYS, and AUTH_DH, MAY be implemented as well.
    </t>

    <section title="Security Mechanisms for NFSv4">

      <t>
        RPCSEC_GSS, via GSS-API, supports multiple mechanisms that provide
        security services.  For interoperability, NFSv4 clients and servers
        MUST support the Kerberos V5 security mechanism.
      </t>

      <t>
        The use of RPCSEC_GSS requires selection of mechanism, quality of
        protection (QOP), and service (authentication, integrity, privacy).
        For the mandated security mechanisms, NFSv4 specifies that a QOP of
        zero is used, leaving it up to the mechanism or the mechanism's
        configuration to map QOP zero to an appropriate level of protection.
        Each mandated mechanism specifies a minimum set of cryptographic
        algorithms for implementing integrity and privacy.  NFSv4 clients
        and servers MUST be implemented on operating environments that comply
        with the required cryptographic algorithms of each required
        mechanism.
      </t>

      <section anchor="krb5:sectrip" title="Kerberos V5 as a Security Triple">
        <t>
          The Kerberos V5 GSS-API mechanism as described in
          <xref target="RFC4121" /> MUST be implemented with the
          RPCSEC_GSS services as specified in
          <xref target='pseudo_flavor' />. Both client and server
          MUST support each of the pseudo-flavors. 
        </t>

        <texttable anchor='pseudo_flavor' title="Mapping Pseudo-Flavor to Service">
          <ttcol>Number</ttcol>
          <ttcol>Name</ttcol>
          <ttcol>Mechanism's OID</ttcol>
          <ttcol>RPCSEC_GSS service</ttcol>

          <c>390003</c>
          <c>krb5</c>
          <c>1.2.840.113554.1.2.2</c>
          <c>rpc_gss_svc_none</c>

          <c>390004</c>
          <c>krb5i</c>
          <c>1.2.840.113554.1.2.2</c>
          <c>rpc_gss_svc_integrity</c>

          <c>390005</c>
          <c>krb5p</c>
          <c>1.2.840.113554.1.2.2</c>
          <c>rpc_gss_svc_privacy</c>

        </texttable>

        <t>
          Note that the pseudo-flavor is presented here as a mapping aid to the
          implementer.  Because this NFS protocol includes a method to negotiate
          security and it understands the GSS-API mechanism, the pseudo-flavor
          is not needed.  The pseudo-flavor is needed for NFSv3 since
          the security negotiation is done via the MOUNT protocol as described
          in <xref target="RFC2623" />.
        </t>

        <t>
          At the time this document was specified, the Advanced Encryption Standard
          (AES) with HMAC-SHA1 was a required algorithm set for Kerberos V5.
          In contrast, when NFSv4.0 was first specified in
          <xref target="RFC3530" />, weaker algorithm sets were
          REQUIRED for Kerberos V5, and were REQUIRED in the NFSv4.0
          specification, because the Kerberos V5 specification at the time did
          not specify stronger algorithms.  The NFSv4 specification does not
          specify required algorithms for Kerberos V5, and instead, the
          implementer is expected to track the evolution of the Kerberos V5
          standard if and when stronger algorithms are specified.
        </t>

        <section toc='exclude' anchor="ss:core_infrastructure:SCfCAiKV" title="Security Considerations for Cryptographic Algorithms in Kerberos V5">
          <t>
            When deploying NFSv4, the strength of the security achieved depends
            on the existing Kerberos V5 infrastructure.  The algorithms of
            Kerberos V5 are not directly exposed to or selectable by the client
            or server, so there is some due diligence required by the user of
            NFSv4 to ensure that security is acceptable where needed. Guidance
            is provided in <xref target="RFC6649" /> as to why weak algorithms
            should be disabled by default.
          </t>
        </section>

      </section>
    </section>
  </section>

  <section title="Security Negotiation">
    <t>
      With the NFSv4 server potentially offering multiple security
      mechanisms, the client needs a method to determine or negotiate
      which mechanism is to be used for its communication with the server.
      The NFS server can have multiple points within its file system
      namespace that are available for use by NFS clients.  In turn, the
      NFS server can be configured such that each of these entry points
      can have different or multiple security mechanisms in use.
    </t>

    <t>
      The security negotiation between client and server SHOULD be done
      with a secure channel to eliminate the possibility of a third party
      intercepting the negotiation sequence and forcing the client and
      server to choose a lower level of security than required or desired.
      See <xref target="sec:security" /> for further discussion.
    </t>

    <section title="SECINFO">
      <t>
        The SECINFO operation will allow the client to determine,
        on a per-filehandle basis, what security triple (see
        <xref target='RFC2743' /> and <xref target="OP_SECINFO_DESCRIPTION"/>)
        is to be used for server access. In general, the client will not
        have to use the SECINFO operation, except during initial
        communication with the server or when the client encounters a
        new security policy as the client navigates the namespace. Either
        condition will force the client to negotiate a new security triple.
      </t>
    </section>

    <section title="Security Error">

      <t>
        Based on the assumption that each NFSv4 client and server
        MUST support a minimum set of security (i.e.,
        Kerberos V5 under RPCSEC_GSS), the NFS client will start its
        communication with the server with one of the minimal security triples.
        During communication with the server, the client can receive an NFS
        error of NFS4ERR_WRONGSEC.  This error allows the server to notify the
        client that the security triple currently being used is not appropriate
        for access to the server's file system resources.  The client is then
        responsible for determining what security triples are available at the
        server and choosing one that is appropriate for the client.  See
        <xref target="OP_SECINFO" /> for further discussion of how the
        client will respond to the NFS4ERR_WRONGSEC error and use SECINFO.
      </t>
    </section>

  <section title="Callback RPC Authentication">

      <t>
        Except as noted elsewhere in this section, the callback RPC (described
        later) MUST mutually authenticate the NFS server to the principal
        that acquired the client ID (also described later), using the security
        flavor of the original SETCLIENTID operation used.
      </t>

      <t>
        For AUTH_NONE, there are no principals, so this is a non-issue.
      </t>

      <t>
        AUTH_SYS has no notions of mutual authentication or a server principal,
        so the callback from the server simply uses the AUTH_SYS credential
        that the user used when he set up the delegation.
      </t>

      <t>
        For AUTH_DH, one commonly used convention is that the server uses
        the credential corresponding to this AUTH_DH principal:

        <figure>
          <artwork>
  unix.host@domain
          </artwork>
        </figure>

        where host and domain are variables corresponding to the name of
        the server host and directory services domain in which it lives,
        such as a Network Information System domain or a DNS domain.
      </t>

      <t>
        Regardless of what security mechanism under RPCSEC_GSS is
        being used, the NFS server MUST identify itself in GSS-API via a
        GSS_C_NT_HOSTBASED_SERVICE name type.  GSS_C_NT_HOSTBASED_SERVICE names
        are of the form:

        <figure>
          <artwork>
  service@hostname
          </artwork>
        </figure>
      </t>

      <t>
        For NFS, the "service" element is:

        <figure>
          <artwork>
  nfs
          </artwork>
        </figure>

        Implementations of security mechanisms will convert nfs@hostname to
        various different forms.  For Kerberos V5, the following
        form is RECOMMENDED:

        <figure>
          <artwork>
  nfs/hostname
          </artwork>
        </figure>
      </t>

      <t>
        For Kerberos V5, nfs/hostname would be a server principal in
        the Kerberos Key Distribution Center database.  This is the same
        principal the client acquired a GSS-API context for when it issued
        the SETCLIENTID operation; therefore, the realm name for the
        server principal must be the same for the callback as it was for
        the SETCLIENTID.
      </t>

    </section>
  </section>
</section>

<section anchor="sec:filehandles" title="Filehandles">
  <t>
    The filehandle in the NFS protocol is a per-server unique identifier
    for a file system object.  The contents of the filehandle are
    opaque to the client.  Therefore, the server is responsible for
    translating the filehandle to an internal representation of the
    file system object.
  </t>

  <section title="Obtaining the First Filehandle">

    <t>
      The operations of the NFS protocol are defined in terms of one or
      more filehandles.  Therefore, the client needs a filehandle to
      initiate communication with the server.  With the NFSv2
      protocol <xref target="RFC1094" /> and the NFSv3 protocol <xref target="RFC1813" />, there
      exists an ancillary protocol to obtain this first filehandle.
      The MOUNT protocol, RPC program number 100005, provides the
      mechanism of translating a string-based file system pathname to
      a filehandle that can then be used by the NFS protocols.
    </t>

    <t>
      The MOUNT protocol has deficiencies in the area of security
      and use via firewalls.  This is one reason that the use of the
      public filehandle was introduced in <xref target="RFC2054" /> and <xref target="RFC2055" />.
      With the use of the public filehandle in combination with the
      LOOKUP operation in the NFSv2 and NFSv3 protocols, it has
      been demonstrated that the MOUNT protocol is unnecessary for
      viable interaction between the NFS client and server.
    </t>

    <t>
      Therefore, the NFSv4 protocol will not use an ancillary
      protocol for translation from string-based pathnames to a
      filehandle.  Two special filehandles will be used as starting
      points for the NFS client.
    </t>

    <section title="Root Filehandle">

      <t>
        The first of the special filehandles is the root filehandle.
        The root filehandle is the "conceptual" root of the file system
        namespace at the NFS server.  The client uses or starts with the
        root filehandle by employing the PUTROOTFH operation.  The
        PUTROOTFH operation instructs the server to set the current
        filehandle to the root of the server's file tree.  Once this
        PUTROOTFH operation is used, the client can then traverse the
        entirety of the server's file tree with the LOOKUP operation.
        A complete discussion of the server namespace is
        in <xref target="sec:name_space" />.
      </t>

    </section>

    <section title="Public Filehandle">

      <t>
        The second special filehandle is the public filehandle.  Unlike the
        root filehandle, the public filehandle may be bound or represent an
        arbitrary file system object at the server.  The server is responsible
        for this binding.  It may be that the public filehandle and the
        root filehandle refer to the same file system object.  However, it
        is up to the administrative software at the server and the policies
        of the server administrator to define the binding of the
        public filehandle and server file system object.  The client may not
        make any assumptions about this binding.  The client uses the
        public filehandle via the PUTPUBFH operation.
      </t>

    </section>

  </section>

  <section title="Filehandle Types">

    <t>
      In the NFSv2 and NFSv3 protocols, there was one type of
      filehandle with a single set of semantics, of which the primary
      one was that it was persistent across a server reboot.  As such, this type of filehandle
      is termed "persistent" in NFSv4.  The semantics of a
      persistent filehandle remain the same as before.  A new type of
      filehandle introduced in NFSv4 is the volatile filehandle,
      which attempts to accommodate certain server environments.
    </t>

    <t>
      The volatile filehandle type was introduced to address server
      functionality or implementation issues that make correct
      implementation of a persistent filehandle infeasible.  Some server
      environments do not provide a file system level invariant that
      can be used to construct a persistent filehandle.  The underlying
      server file system may not provide the invariant, or the server's
      file system programming interfaces may not provide access to the
      needed invariant.  Volatile filehandles may ease the implementation
      of server functionality, such as hierarchical storage management
      or file system reorganization or migration.  However, the volatile
      filehandle increases the implementation burden for the client.
    </t>

    <t>
      Since the client will need to handle persistent and volatile
      filehandles differently, a file attribute is defined that may
      be used by the client to determine the filehandle types being
      returned by the server.
    </t>

    <section title="General Properties of a Filehandle">

      <t>
        The filehandle contains all the information the server needs to
        distinguish an individual file.  To the client, the filehandle is
        opaque.  The client stores filehandles for use in a later request and
        can compare two filehandles from the same server for equality
        by doing a byte-by-byte comparison.  However, the client MUST
        NOT otherwise interpret the contents of filehandles.  If
        two filehandles from the same server are equal, they MUST
        refer to the same file.  However, it is not required that
        two different filehandles refer to different file system
        objects. Servers SHOULD try to maintain a one-to-one
        correspondence between filehandles and file system objects
        but there may be situations in which the mapping is not
        one-to-one.  Clients MUST use filehandle comparisons only
        to improve performance, not for correct behavior.  All
        clients need to be prepared for situations in which it
        cannot be determined whether two different filehandles
        denote the same object and in such cases need to avoid assuming
        that objects denoted are different, as this might cause
        incorrect behavior.  Further discussion of filehandle and
        attribute comparison in the context of data caching is
        presented in <xref target="ss:cc:dcfi" />.
      </t>

      <t>
        As an example, in the case that two different pathnames when
        traversed at the server terminate at the same file system object,
        the server SHOULD return the same filehandle for each path.
        This can occur if a hard link is used to create two filenames
        that refer to the same underlying file object and associated data.
        For example, if paths /a/b/c and /a/d/c refer to the same file,
        the server SHOULD return the same filehandle for both pathname
        traversals.
      </t>

    </section>

    <section title="Persistent Filehandle">

      <t>
        A persistent filehandle is defined as having a fixed value for the
        lifetime of the file system object to which it refers.  Once the
        server creates the filehandle for a file system object, the server
        MUST accept the same filehandle for the object for the lifetime of
        the object.  If the server restarts or reboots, the NFS server must
        honor the same filehandle value as it did in the server's previous
        instantiation.  Similarly, if the file system is migrated, the new
        NFS server must honor the same filehandle as the old NFS server.
      </t>

      <t>
        The persistent filehandle will become stale or invalid when
        the file system object is removed.  When the server is presented
        with a persistent filehandle that refers to a deleted object,
        it MUST return an error of NFS4ERR_STALE.  A filehandle may
        become stale when the file system containing the object is no
        longer available.  The file system may become unavailable if it
        exists on removable media and the media is no longer available at
        the server, or if the file system in whole has been destroyed,
        or if the file system has simply been removed from the server's
        namespace (i.e., unmounted in a UNIX environment).
      </t>

    </section>

    <section title="Volatile Filehandle">

      <t>
        A volatile filehandle does not share the same longevity
        characteristics of a persistent filehandle.  The server may
        determine that a volatile filehandle is no longer valid at
        many different points in time.  If the server can definitively
        determine that a volatile filehandle refers to an object that has
        been removed, the server should return NFS4ERR_STALE to the client
        (as is the case for persistent filehandles).  In all other cases
        where the server determines that a volatile filehandle can no
        longer be used, it should return an error of NFS4ERR_FHEXPIRED.
      </t>

      <t>
        The REQUIRED attribute "fh_expire_type" is used by the client
        to determine what type of filehandle the server is providing for
        a particular file system.  This attribute is a bitmask with the
        following values:

        <list style='hanging'>
          <t hangText="FH4_PERSISTENT:">
             The value of FH4_PERSISTENT is used to indicate a
             persistent filehandle, which is valid until the object is
             removed from the file system.  The server will not return
             NFS4ERR_FHEXPIRED for this filehandle.  FH4_PERSISTENT is
             defined as a value in which none of the bits specified
             below are set.
          </t>

          <t hangText="FH4_VOLATILE_ANY:">
             The filehandle may expire at any time, except as
             specifically excluded (i.e., FH4_NOEXPIRE_WITH_OPEN).
          </t>

          <t hangText="FH4_NOEXPIRE_WITH_OPEN:">
             May only be set when FH4_VOLATILE_ANY is set.  If this bit
             is set, then the meaning of FH4_VOLATILE_ANY is qualified
             to exclude any expiration of the filehandle when it is
             open.
          </t>

          <t hangText="FH4_VOL_MIGRATION:">
             The filehandle will expire as a result of migration.  If
             FH4_VOLATILE_ANY is set, FH4_VOL_MIGRATION is redundant.
          </t>

          <t hangText="FH4_VOL_RENAME:">
             The filehandle will expire during rename.  This includes a
             rename by the requesting client or a rename by any other
             client.  If FH4_VOLATILE_ANY is set, FH4_VOL_RENAME is
             redundant.
          </t>
        </list>
      </t>

      <t>
        Servers that provide volatile filehandles that may expire while
        open (i.e., if FH4_VOL_MIGRATION or FH4_VOL_RENAME is set or if
        FH4_VOLATILE_ANY is set and FH4_NOEXPIRE_WITH_OPEN is not set)
        should deny a RENAME or REMOVE that would affect an OPEN file
        of any of the components leading to the OPEN file.  In addition,
        the server SHOULD deny all RENAME or REMOVE requests during the
        grace period upon server restart.
      </t>

      <t>
        Note that the bits FH4_VOL_MIGRATION and FH4_VOL_RENAME allow the
        client to determine that expiration has occurred whenever a specific
        event occurs, without an explicit filehandle expiration error from
        the server.  FH4_VOLATILE_ANY does not provide this form of
        information. In situations where the server will expire many, but
        not all, filehandles upon migration (e.g., all but those that are
        open), FH4_VOLATILE_ANY (in this case, with FH4_NOEXPIRE_WITH_OPEN)
        is a better choice since the client may not assume that all
        filehandles will expire when migration occurs, and it is likely
        that additional expirations will occur (as a result of file CLOSE)
        that are separated in time from the migration event itself.
      </t>

    </section>

    <section title="One Method of Constructing a Volatile Filehandle">

      <t>
        A volatile filehandle, while opaque to the client, could contain:

        <figure>
          <artwork>
  [volatile bit = 1 | server boot time | slot | generation number]
          </artwork>
        </figure>

        <list style='symbols'>
          <t>
            slot is an index in the server volatile filehandle table
          </t>

          <t>
            generation number is the generation number for the table
            entry/slot
          </t>
        </list>
      </t>

      <t>
        When the client presents a volatile filehandle, the server makes the
        following checks, which assume that the check for the volatile bit
        has passed.  If the server boot time is less than the current server
        boot time, return NFS4ERR_FHEXPIRED.  If slot is out of range, return
        NFS4ERR_BADHANDLE.  If the generation number does not match,
        return NFS4ERR_FHEXPIRED.
      </t>

      <t>
        When the server reboots, the table is gone (it is volatile).
      </t>

      <t>
        If the volatile bit is 0, then it is a persistent filehandle with a
        different structure following it.
      </t>

    </section>
  </section>

  <section title="Client Recovery from Filehandle Expiration">

    <t>
      If possible, the client should recover from the receipt of an
      NFS4ERR_FHEXPIRED error.  The client must take on additional
      responsibility so that it may prepare itself to recover from the
      expiration of a volatile filehandle.  If the server returns
      persistent filehandles, the client does not need these additional
      steps.
    </t>

    <t>
      For volatile filehandles, most commonly the client will need to store
      the component names leading up to and including the file system object
      in question.  With these names, the client should be able to recover
      by finding a filehandle in the namespace that is still available
      or by starting at the root of the server's file system namespace.
    </t>

    <t>
      If the expired filehandle refers to an object that has been
      removed from the file system, obviously the client will not be
      able to recover from the expired filehandle.
    </t>

    <t>
      It is also possible that the expired filehandle refers to a file
      that has been renamed.  If the file was renamed by another client,
      again it is possible that the original client will not be able to
      recover.  However, in the case that the client itself is renaming
      the file and the file is open, it is possible that the client may
      be able to recover.  The client can determine the new pathname
      based on the processing of the rename request.  The client can
      then regenerate the new filehandle based on the new pathname.
      The client could also use the COMPOUND operation mechanism to
      construct a set of operations like:

      <figure>
        <artwork>
  RENAME A B
  LOOKUP B
  GETFH
        </artwork>
      </figure>
    </t>

    <t>
      Note that the COMPOUND procedure does not provide atomicity.
      This example only reduces the overhead of recovering from an
      expired filehandle.
    </t>
  </section>
</section>

<section anchor="file_attributes" title="Attributes">
  <t>
    To meet the requirements of extensibility and increased
    interoperability with non-UNIX platforms, attributes need to be handled
    in a flexible manner.  The NFSv3 fattr3 structure contains a
    fixed list of attributes that not all clients and servers are able to
    support or care about.  The fattr3 structure cannot be extended as
    new needs arise, and it provides no way to indicate non-support.  With
    the NFSv4.0 protocol, the client is able to query what attributes
    the server supports and construct requests with only those supported
    attributes (or a subset thereof).
  </t>
  <t>
    To this end, attributes are divided into three groups: REQUIRED,
    RECOMMENDED, and named.  Both REQUIRED and RECOMMENDED attributes are
    supported in the NFSv4.0 protocol by a specific and well-defined
    encoding and are identified by number.  They are requested by setting
    a bit in the bit vector sent in the GETATTR request; the server
    response includes a bit vector to list what attributes were returned
    in the response.  New REQUIRED or RECOMMENDED attributes may be added
    to the NFSv4 protocol as part of a new minor version by publishing a
    Standards Track RFC that allocates a new attribute number value and
    defines the encoding for the attribute.  See <xref target="sec:minor"/>
    for further discussion.
  </t>
  <t>
    Named attributes are accessed by the OPENATTR operation, which
    accesses a hidden directory of attributes associated with a file
    system object.  OPENATTR takes a filehandle for the object and returns
    the filehandle for the attribute hierarchy.  The filehandle for the
    named attributes is a directory object accessible by LOOKUP or READDIR
    and contains files whose names represent the named attributes and
    whose data bytes are the value of the attribute.  For example:
  </t>
  <texttable>
    <ttcol align='left' />
    <ttcol align='left' />
    <ttcol align='left' />
    <c>LOOKUP</c><c>"foo"</c><c>; look up file</c>
    <c>GETATTR</c><c>attrbits</c><c />
    <c>OPENATTR</c><c /><c>; access foo's named attributes</c>
    <c>LOOKUP</c><c>"x11icon"</c><c>; look up specific attribute</c>
    <c>READ</c><c>0,4096</c><c>; read stream of bytes</c>
  </texttable>
  <t>
    Named attributes are intended for data needed by applications rather
    than by an NFS client implementation.  NFS implementers are strongly
    encouraged to define their new attributes as RECOMMENDED attributes by
    bringing them to the IETF Standards Track process.
  </t>
  <t>
    The set of attributes that are classified as REQUIRED is
    deliberately small since servers need to do whatever it takes to support
    them.  A server should support as many of the RECOMMENDED attributes
    as possible; however, by their definition, the server is not required to
    support all of them.  Attributes are deemed REQUIRED if the data is
    both needed by a large number of clients and is not otherwise
    reasonably computable by the client when support is not provided on
    the server.
  </t>
  <t>
    Note that the hidden directory returned by OPENATTR is a convenience
    for protocol processing.  The client should not make any assumptions
    about the server's implementation of named attributes and whether or
    not the underlying file system at the server has a named attribute
    directory.  Therefore, operations such as SETATTR and GETATTR on the
    named attribute directory are undefined.
  </t>
  <section anchor="mandatory_attributes_intro" title="REQUIRED Attributes">
    <t>
      These attributes MUST be supported by every NFSv4.0 client and
      server in order to ensure a minimum level of interoperability.
      The server MUST store and return these attributes, and the client
      MUST be able to function with an attribute set limited to these
      attributes.  With just the REQUIRED attributes, some client
      functionality can be impaired or limited in some ways.  A client
      can ask for any of these attributes to be returned by setting a
      bit in the GETATTR request. For each such bit set, the server
      MUST return the corresponding attribute value.
    </t>
  </section>
  <section anchor="recommended_attributes_intro" title="RECOMMENDED Attributes">
    <t>
      These attributes are understood well enough to warrant support in the
      NFSv4.0 protocol.  However, they may not be supported on all
      clients and servers.  A client MAY ask for any of these attributes to
      be returned by setting a bit in the GETATTR request but MUST handle
      the case where the server does not return them.  A client MAY ask for
      the set of attributes the server supports and SHOULD NOT request
      attributes the server does not support.  A server should be tolerant
      of requests for unsupported attributes and simply not return them,
      rather than considering the request an error.  It is expected that
      servers will support all attributes they comfortably can and only fail
      to support attributes that are difficult to support in their
      operating environments.  A server should provide attributes whenever
      they don't have to "tell lies" to the client.  For example, a file
      modification time either should be an accurate time or should not be
      supported by the server.  At times this will be difficult for
      clients, but a client is better positioned to decide whether and how to
      fabricate or construct an attribute or whether to do without the
      attribute.
    </t>
  </section>
  <section anchor="named_attributes_intro" title="Named Attributes">
    <t>
      These attributes are not supported by direct encoding in the NFSv4 
      protocol but are accessed by string names rather than
      numbers and correspond to an uninterpreted stream of bytes that are
      stored with the file system object.  The namespace for these
      attributes may be accessed by using the OPENATTR operation.  The
      OPENATTR operation returns a filehandle for a virtual "named attribute
      directory", and further perusal and modification of the namespace may 
      be done using operations that work on more typical directories.  In
      particular, READDIR may be used to get a list of such named attributes,
      and LOOKUP and OPEN may select a particular attribute.  Creation of
      a new named attribute may be the result of an OPEN specifying file
      creation.
    </t>
    <t>
      Once an OPEN is done, named attributes may be examined and changed 
      by normal READ and WRITE operations using the filehandles and stateids
      returned by OPEN.
    </t>
    <t>
      Named attributes and the named attribute directory may have 
      their own (non-named) attributes.  Each of these objects must have all 
      of the REQUIRED attributes and may have additional RECOMMENDED 
      attributes.  However, the set of attributes for named attributes 
      and the named attribute directory need not be, and
      typically will not be, as large as that for other objects in that 
      file system.
    </t>
    <t>
      Named attributes might be the target of delegations.  However, since
      granting of delegations is at the server's discretion, a server
      need not support delegations on named attributes.
    </t>
    <t>
      It is RECOMMENDED that servers support arbitrary named attributes.  A
      client should not depend on the ability to store any named attributes
      in the server's file system.  If a server does support named
      attributes, a client that is also able to handle them should be able
      to copy a file's data and metadata with complete transparency from
      one location to another; this would imply that names allowed for
      regular directory entries are valid for named attribute names as well.
    </t>
    <t>
      In NFSv4.0, the structure of named attribute directories is 
      restricted in a number of ways, in order to prevent the development
      of non-interoperable implementations in which some servers support
      a fully general hierarchical directory structure for named attributes
      while others support a limited but adequate structure for named
      attributes.  In such an environment, clients or applications might come to
      depend on non-portable extensions.  The restrictions are:
      <list style="symbols">
        <t>
          CREATE is not allowed in a named attribute directory.  Thus, such
          objects as symbolic links and special files are not allowed to
          be named attributes.   Further, directories may not be created
          in a named attribute directory, so no hierarchical structure of
          named attributes for a single object is allowed.
        </t>
        <t>
          If OPENATTR is done on a named attribute directory or on
          a named attribute, the server MUST return an error.
        </t>
        <t>
          Doing a RENAME of a named attribute to a different named 
          attribute directory or to an ordinary (i.e., non-named-attribute)
          directory is not allowed.
        </t>
        <t>
          Creating hard links between named attribute directories or 
          between named attribute directories and ordinary directories 
          is not allowed.
        </t>
      </list>
    </t>
    <t>
      Names of attributes will not be controlled by this document or other
      IETF Standards Track documents.  See <xref target="sec:iana"/>
      for further discussion.
    </t>
  </section>
  <section title="Classification of Attributes">
    <t>
      Each of the attributes accessed using SETATTR and GETATTR (i.e.,
      REQUIRED and RECOMMENDED attributes) can be classified
      in one of three categories:

      <list style='numbers'>
        <t>
          per-server attributes for which the value of the attribute
          will be the same for all file objects that share the same
          server.
        </t>

        <t>
          per-file system attributes for which the value of the attribute
          will be the same for some or all file objects that share the
          same server and  fsid attribute (<xref target='attrdef_fsid' />).
          See below for details regarding when such sharing is in effect.
        </t>

        <t>
          per-file system object attributes.
        </t>
      </list>
    </t>

    <t>
      The handling of per-file system attributes depends on the
      particular attribute and the setting of the homogeneous
      (<xref target='attrdef_homogeneous' />) attribute. The
      following rules apply:

      <list style='numbers'>
        <t>
          The values of the attributes supported_attrs, fsid, homogeneous,
          link_support, and symlink_support are always common to all
          objects within the given file system.
        </t>

        <t>
          For other attributes, different values may be returned for
          different file system objects if the attribute homogeneous
          is supported within the file system in question and has
          the value false.
        </t>
      </list>
    </t>

    <t>
      The classification of attributes is as follows.  Note that
      the attributes time_access_set and time_modify_set are not
      listed in this section, because they are write-only attributes
      corresponding to time_access and time_modify and are used
      in a special instance of SETATTR.

      <list style='symbols'>
        <t>
          The per-server attribute is:
          <list style='empty'>
            <t>
              lease_time
            </t>
          </list>
        </t>
        <t>
          The per-file system attributes are:
          <list style='empty'>
            <t>
              supported_attrs, fh_expire_type, link_support,
              symlink_support, unique_handles, aclsupport,
              cansettime, case_insensitive, case_preserving,
              chown_restricted, files_avail, files_free,
              files_total, fs_locations, homogeneous, maxfilesize,
              maxname, maxread, maxwrite, no_trunc, space_avail,
              space_free, space_total, and time_delta
            </t>
          </list>
        </t>    
        <t>
          The per-file system object attributes are:
          <list style='empty'>
            <t>
              type, change, size, named_attr, fsid, rdattr_error,
              filehandle, acl, archive, fileid, hidden, maxlink,
              mimetype, mode, numlinks, owner, owner_group, rawdev,
              space_used, system, time_access, time_backup,
              time_create, time_metadata, time_modify, and
              mounted_on_fileid
            </t>
          </list>
        </t>
      </list>
    </t>
    <t>
      For quota_avail_hard, quota_avail_soft, and quota_used, see their
      definitions below for the appropriate classification.
    </t>

  </section>

  <section anchor="rw_attr" 
           title="Set-Only and Get-Only Attributes">
    <t>
     Some REQUIRED and RECOMMENDED attributes are set-only; i.e., they
     can be set via SETATTR but not retrieved via GETATTR. Similarly, some
     REQUIRED and RECOMMENDED attributes are get-only; i.e., they
     can be retrieved via GETATTR but not set via SETATTR. If a client attempts
     to set a get-only attribute or get a set-only attribute, the server
     MUST return NFS4ERR_INVAL.
   </t>

  </section>

  <section anchor="mandatory_attributes" 
           title="REQUIRED Attributes - List and Definition References">
    <t>
     The list of REQUIRED attributes appears in <xref target="req_attr_table"/>.
     The meanings of the columns of the table are:
     <list style='symbols'>
     <t>Name: The name of the attribute.</t>
     <t>ID: The number assigned to the attribute. In
        the event of conflicts between the assigned number and <xref
        target="RFC7531"/>, the latter is
        authoritative, but in such an event, it should be resolved with
        errata to this document and/or <xref target="RFC7531"/>.
        See <xref target="IESG_ERRATA"/> for the errata process.</t>
     <t>Data Type: The XDR data type of the attribute.</t>
     <t>
        Acc: Access allowed to the attribute. R means
        read-only (GETATTR may retrieve, SETATTR may not
        set). W means write-only (SETATTR may set, GETATTR
        may not retrieve).  R W means read/write (GETATTR
        may retrieve, SETATTR may set).

     </t>
     <t>Defined in: The section of this specification that describes the
        attribute.</t>
     </list>
    </t>

    <texttable anchor="req_attr_table" title="REQUIRED Attributes">
      <ttcol align='left' >Name</ttcol>
      <ttcol align='left' >ID</ttcol>
      <ttcol align='left' >Data Type</ttcol>
      <ttcol align='left' >Acc</ttcol>
      <ttcol align='left' >Defined in</ttcol>

      <c>supported_attrs</c><c>0</c><c>bitmap4</c><c>R</c>
      <c>
        <xref target="attrdef_supp_attr" />
      </c>

      <c>type</c><c>1</c><c>nfs_ftype4</c><c>R</c>
      <c>
        <xref target="attrdef_type"  />
      </c>

      <c>fh_expire_type</c><c>2</c><c>uint32_t</c><c>R</c>
      <c>
        <xref target="attrdef_fh_expire_type"  />
      </c>

      <c>change</c><c>3</c><c>changeid4</c><c>R</c>
      <c>
        <xref target="attrdef_change"  />
      </c>
      
      <c>size</c><c>4</c><c>uint64_t</c><c>R W</c>
      <c>
        <xref target="attrdef_size" />
      </c>

      <c>link_support</c><c>5</c><c>bool</c><c>R</c>
      <c>
        <xref target="attrdef_link_support" />
      </c>

      <c>symlink_support</c><c>6</c><c>bool</c><c>R</c>
      <c>
        <xref target="attrdef_symlink_support" />
      </c>

      <c>named_attr</c><c>7</c><c>bool</c><c>R</c>
      <c>
        <xref target="attrdef_named_attr" />
      </c>

      <c>fsid</c><c>8</c><c>fsid4</c><c>R</c>
      <c>
        <xref target="attrdef_fsid" />
      </c>

      <c>unique_handles</c><c>9</c><c>bool</c><c>R</c>
      <c>
        <xref target="attrdef_unique_handles" />
      </c>

      <c>lease_time</c><c>10</c><c>nfs_lease4</c><c>R</c>
      <c>
        <xref target="attrdef_lease_time" />
      </c>

      <c>rdattr_error</c><c>11</c><c>nfsstat4</c><c>R</c>
      <c>
        <xref target="attrdef_rdattr_error" />
      </c>

      <c>filehandle</c><c>19</c><c>nfs_fh4</c><c>R</c>
      <c>
        <xref target="attrdef_filehandle" />
      </c>

    </texttable>
  </section>
  <section anchor="recommended_attributes" 
           title="RECOMMENDED Attributes - List and Definition References">
    <t>
     The RECOMMENDED attributes are defined in
     <xref target="rec_attr_tbl"/>.  The meanings
     of the column headers are the same as
     <xref target="req_attr_table"/>; see <xref
     target="mandatory_attributes" /> for the meanings.

    </t>
    <texttable anchor="rec_attr_tbl" title="RECOMMENDED Attributes">
      <ttcol align='left' >Name</ttcol>
      <ttcol align='left' >ID</ttcol>
      <ttcol align='left' >Data Type</ttcol>
      <ttcol align='left' >Acc</ttcol>
      <ttcol align='left' >Defined in</ttcol>

      <c>acl</c><c>12</c><c>nfsace4&lt;></c><c>R W</c>
      <c>
        <xref target="attrdef_acl" />
      </c>

      <c>aclsupport</c><c>13</c><c>uint32_t</c><c>R</c>
      <c>
        <xref target="attrdef_aclsupport" />
      </c>

      <c>archive</c><c>14</c><c>bool</c><c>R W</c>
      <c>
        <xref target="attrdef_archive" />
      </c>

      <c>cansettime</c><c>15</c><c>bool</c><c>R</c>
      <c>
        <xref target="attrdef_cansettime" />
      </c>

      <c>case_insensitive</c><c>16</c><c>bool</c><c>R</c>
      <c>
        <xref target="attrdef_case_insensitive" />
      </c>

      <c>case_preserving</c><c>17</c><c>bool</c><c>R</c>
      <c>
        <xref target="attrdef_case_preserving" />
      </c>

      <c>chown_restricted</c><c>18</c><c>bool</c><c>R</c>
      <c>
        <xref target="attrdef_chown_restricted" />
      </c>

      <c>fileid</c><c>20</c><c>uint64_t</c><c>R</c>
      <c>
        <xref target="attrdef_fileid" />
      </c>

      <c>files_avail</c><c>21</c><c>uint64_t</c><c>R</c>
      <c>
        <xref target="attrdef_files_avail" />
      </c>

      <c>files_free</c><c>22</c><c>uint64_t</c><c>R</c>
      <c>
        <xref target="attrdef_files_free" />
      </c>

      <c>files_total</c><c>23</c><c>uint64_t</c><c>R</c>
      <c>
        <xref target="attrdef_files_total" />
      </c>

      <c>fs_locations</c><c>24</c><c>fs_locations4</c><c>R</c>
      <c>
        <xref target="attrdef_fs_locations" />
      </c>

      <c>hidden</c><c>25</c><c>bool</c><c>R W</c>
      <c>
        <xref target="attrdef_hidden" />
      </c>

      <c>homogeneous</c><c>26</c><c>bool</c><c>R</c>
      <c>
        <xref target="attrdef_homogeneous" />
      </c>

      <c>maxfilesize</c><c>27</c><c>uint64_t</c><c>R</c>
      <c>
        <xref target="attrdef_maxfilesize" />
      </c>

      <c>maxlink</c><c>28</c><c>uint32_t</c><c>R</c>
      <c>
        <xref target="attrdef_maxlink" />
      </c>

      <c>maxname</c><c>29</c><c>uint32_t</c><c>R</c>
      <c>
        <xref target="attrdef_maxname" />
      </c>

      <c>maxread</c><c>30</c><c>uint64_t</c><c>R</c>
      <c>
        <xref target="attrdef_maxread" />
      </c>

      <c>maxwrite</c><c>31</c><c>uint64_t</c><c>R</c>
      <c>
        <xref target="attrdef_maxwrite" />
      </c>

      <c>mimetype</c><c>32</c><c>ascii_ REQUIRED4&lt;&gt;</c><c>R W</c>
      <c>
        <xref target="attrdef_mimetype" />
      </c>

      <c>mode</c><c>33</c><c>mode4</c><c>R W</c>
      <c>
        <xref target="attrdef_mode" />
      </c>

      <c>mounted_on_fileid</c><c>55</c><c>uint64_t</c><c>R</c>
      <c>
        <xref target="attrdef_mounted_on_fileid" />
      </c>

      <c>no_trunc</c><c>34</c><c>bool</c><c>R</c>
      <c>
        <xref target="attrdef_no_trunc" />
      </c>

      <c>numlinks</c><c>35</c><c>uint32_t</c><c>R</c>
      <c>
        <xref target="attrdef_numlinks" />
      </c>

      <c>owner</c>
      <c>36</c><c>utf8str_mixed</c><c>R W</c>
      <c>
        <xref target="attrdef_owner" />
      </c>

      <c>owner_group</c>
      <c>37</c><c>utf8str_mixed</c><c>R W</c>
      <c>
        <xref target="attrdef_owner_group" />
      </c>

      <c>quota_avail_hard</c>
      <c>38</c><c>uint64_t</c><c>R</c>
      <c>
        <xref target="attrdef_quota_avail_hard" />
      </c>

      <c>quota_avail_soft</c>
      <c>39</c><c>uint64_t</c><c>R</c>
      <c>
        <xref target="attrdef_quota_avail_soft" />
      </c>

      <c>quota_used</c>
      <c>40</c><c>uint64_t</c><c>R</c>
      <c>
        <xref target="attrdef_quota_used" />
      </c>

      <c>rawdev</c><c>41</c><c>specdata4</c><c>R</c>
      <c>
        <xref target="attrdef_rawdev" />
      </c>

      <c>space_avail</c><c>42</c><c>uint64_t</c><c>R</c>
      <c>
        <xref target="attrdef_space_avail" />
      </c>

      <c>space_free</c><c>43</c><c>uint64_t</c><c>R</c>
      <c>
        <xref target="attrdef_space_free" />
      </c>

      <c>space_total</c><c>44</c><c>uint64_t</c><c>R</c>
      <c>
        <xref target="attrdef_space_total" />
      </c>

      <c>space_used</c><c>45</c><c>uint64_t</c><c>R</c>
      <c>
        <xref target="attrdef_space_used" />
      </c>

      <c>system</c><c>46</c><c>bool</c><c>R W</c>
      <c>
        <xref target="attrdef_system" />
      </c>

      <c>time_access</c>
      <c>47</c><c>nfstime4</c><c>R</c>
      <c>
        <xref target="attrdef_time_access" />
      </c>

      <c>time_access_set</c><c>48</c><c>settime4</c><c>&nbsp;&nbsp;W</c>
      <c>
        <xref target="attrdef_time_access_set" />
      </c>

      <c>time_backup</c><c>49</c><c>nfstime4</c><c>R W</c>
      <c>
        <xref target="attrdef_time_backup" />
      </c>

      <c>time_create</c><c>50</c><c>nfstime4</c><c>R W</c>
      <c>
        <xref target="attrdef_time_create" />
      </c>

      <c>time_delta</c><c>51</c><c>nfstime4</c><c>R</c>
      <c>
        <xref target="attrdef_time_delta" />
      </c>

      <c>time_metadata</c><c>52</c><c>nfstime4</c><c>R</c>
      <c>
        <xref target="attrdef_time_metadata" />
      </c>

      <c>time_modify</c><c>53</c><c>nfstime4</c><c>R</c>
      <c>
        <xref target="attrdef_time_modify" />
      </c>

      <c>time_modify_set</c><c>54</c><c>settime4</c><c>&nbsp;&nbsp;W</c>
      <c>
        <xref target="attrdef_time_modify_set" />
      </c>

    </texttable>
  </section>

  <section anchor="attribute_definitions" title="Attribute Definitions">

   <section anchor="required_attr" title="Definitions of REQUIRED Attributes">

    <section toc="exclude" anchor="attrdef_supp_attr" 
             title="Attribute 0: supported_attrs">
        <t>
        The bit vector that would retrieve all REQUIRED and
        RECOMMENDED attributes that are supported for this object.
        The scope of this attribute applies to all objects with a
        matching fsid.
        </t>
    </section>

    <section toc="exclude" anchor="attrdef_type" 
             title="Attribute 1: type">
        <t>
          Designates the type of an object in terms of one of a number
          of special constants:
          <list style="symbols">
            <t>
              NF4REG designates a regular file.
            </t>
            <t>
              NF4DIR designates a directory.
            </t>
            <t>
              NF4BLK designates a block device special file.
            </t>
            <t>
              NF4CHR designates a character device special file.
            </t>
            <t>
              NF4LNK designates a symbolic link.
            </t>
            <t>
              NF4SOCK designates a named socket special file.
            </t>
            <t>
              NF4FIFO designates a fifo special file.
            </t>
            <t>
              NF4ATTRDIR designates a named attribute directory.
            </t>
            <t>
              NF4NAMEDATTR designates a named attribute.
            </t>
          </list>
        </t>
        <t>
          Within the explanatory text and operation descriptions, the
          following phrases will be used with the meanings given below:
          <list style="symbols">
            <t>
              The phrase "is a directory" means that the object's
              type attribute is NF4DIR or NF4ATTRDIR.
            </t>
            <t>
              The phrase "is a special file" means that the object's
              type attribute is NF4BLK, NF4CHR, NF4SOCK, or NF4FIFO. 
            </t>
            <t>
              The phrase "is a regular file" means that the object's
              type attribute is NF4REG or NF4NAMEDATTR.
            </t>
            <t>
              The phrase "is a symbolic link" means that the object's
              type attribute is NF4LNK.
            </t>
          </list>
        </t>

    </section>

    <section toc="exclude" anchor="attrdef_fh_expire_type" 
             title="Attribute 2: fh_expire_type">
        <t>
          The server uses this to specify filehandle expiration behavior
          to the client.  See <xref target="sec:filehandles"/> for additional
          description.
        </t>
    </section>

    <section toc="exclude" anchor="attrdef_change" 
             title="Attribute 3: change">
        <t>
          A value created by the server that the client can use to
          determine if file data, directory contents, or attributes of
          the object have been modified.  The server MAY return the
          object's time_metadata attribute for this attribute's value
          but only if the file system object cannot be updated more
          frequently than the resolution of time_metadata.
        </t>
    </section>

    <section toc="exclude" anchor="attrdef_size" 
             title="Attribute 4: size">
        <t>
          The size of the object in bytes.
        </t>
    </section>

    <section toc="exclude" anchor="attrdef_link_support" 
             title="Attribute 5: link_support">
        <t>
          TRUE, if the object's file system supports hard links.
        </t>
    </section>

    <section toc="exclude" anchor="attrdef_symlink_support" 
             title="Attribute 6: symlink_support">
        <t>
          TRUE, if the object's file system supports symbolic links.
        </t>
    </section>

    <section toc="exclude" anchor="attrdef_named_attr" 
             title="Attribute 7: named_attr">
        <t>
          TRUE, if this object has named attributes. In other words,
          this object has a non-empty named attribute directory.
        </t>
    </section>

    <section toc="exclude" anchor="attrdef_fsid" 
             title="Attribute 8: fsid">
        <t>
          Unique file system identifier for the file system holding this
          object.  The fsid attribute has major and minor components, each of
          which are of data type uint64_t.
        </t>
    </section>

    <section toc="exclude" anchor="attrdef_unique_handles" 
             title="Attribute 9: unique_handles">
        <t>
          TRUE, if two distinct filehandles are guaranteed to refer to two
          different file system objects.
        </t>
    </section>

    <section toc="exclude" anchor="attrdef_lease_time" 
             title="Attribute 10: lease_time">
        <t>
          Duration of the lease at the server in seconds.
        </t>
    </section>

    <section toc="exclude" anchor="attrdef_rdattr_error" 
             title="Attribute 11: rdattr_error">
        <t>
          Error returned from an attempt to retrieve attributes during a READDIR operation.
        </t>
    </section>

    <section toc="exclude" anchor="attrdef_filehandle" 
             title="Attribute 19: filehandle">
        <t>
          The filehandle of this object (primarily for READDIR requests).
        </t>
    </section>

   </section>

   <section anchor="recommended_attr" title="Definitions of Uncategorized RECOMMENDED Attributes">
    <t>
     The definitions of most of the RECOMMENDED attributes follow. Collections
     that share a common category are defined in other sections.
    </t>

    <section toc="exclude" anchor="attrdef_archive"
             title="Attribute 14: archive">
      <t>
        TRUE, if this file has been archived since the time of the last
        modification (deprecated in favor of time_backup).
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_cansettime"
             title="Attribute 15: cansettime">
      <t>
        TRUE, if the server is able to change the times for a
        file system object as specified in a SETATTR operation.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_case_insensitive"
             title="Attribute 16: case_insensitive">
      <t>
        TRUE, if filename comparisons on this file system are case
        insensitive.  This refers only to comparisons, and not to
        the case in which filenames are stored.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_case_preserving"
             title="Attribute 17: case_preserving">
      <t>
        TRUE, if the filename case on this file system is preserved.
        This refers only to how filenames are stored, and not to
        how they are compared.  Filenames stored in mixed case
        might be compared using either case-insensitive or
        case-sensitive comparisons.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_chown_restricted"
             title="Attribute 18: chown_restricted">
      <t>
        If TRUE, the server will reject any request to change either
        the owner or the group associated with a file if the caller
        is not a privileged user (for example, "root" in UNIX
        operating environments or the "Take Ownership" privilege
        in Windows 2000).
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_fileid"
             title="Attribute 20: fileid">
      <t>
        A number uniquely identifying the file within the file system.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_files_avail"
             title="Attribute 21: files_avail">
      <t>
        File slots available to this user on the file system
        containing this object -- this should be the smallest
        relevant limit.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_files_free"
             title="Attribute 22: files_free">
      <t>
        Free file slots on the file system containing this
        object -- this should be the smallest relevant limit.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_files_total"
             title="Attribute 23: files_total">
      <t>
        Total file slots on the file system containing this object.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_fs_locations"
            title="Attribute 24: fs_locations">
       <t>
       Locations where this file system may be found.  If the server
       returns NFS4ERR_MOVED as an error, this attribute MUST be
       supported.
       </t>
       <t>
       The server specifies the rootpath for a given server by returning
       a path consisting of zero path components.
       </t>
    </section>

    <section toc="exclude" anchor="attrdef_hidden"
             title="Attribute 25: hidden">
      <t>
        TRUE, if the file is considered hidden with respect to 
        the Windows API.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_homogeneous"
             title="Attribute 26: homogeneous">
      <t>
        TRUE, if this object's file system is homogeneous, i.e., all
        objects in the file system (all objects on the server with the
        same fsid) have common values for all per-file system attributes.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_maxfilesize"
             title="Attribute 27: maxfilesize">
      <t>
        Maximum supported file size for the file system of this object.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_maxlink"
             title="Attribute 28: maxlink">
      <t>
        Maximum number of hard links for this object.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_maxname"
             title="Attribute 29: maxname">
      <t>
        Maximum filename size supported for this object.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_maxread"
             title="Attribute 30: maxread">
      <t>
        Maximum amount of data the READ operation will return for this
        object.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_maxwrite"
             title="Attribute 31: maxwrite">
      <t>
        Maximum amount of data the WRITE operation will accept for this
        object.  This attribute SHOULD be supported if the file is writable.
        Lack of this attribute can lead to the client either wasting
        bandwidth or not receiving the best performance.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_mimetype"
             title="Attribute 32: mimetype">
      <t>
        MIME media type/subtype of this object.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_mounted_on_fileid"
             title="Attribute 55: mounted_on_fileid">
      <t>
        Like fileid, but if the target filehandle is the root of a
        file system, this attribute represents the fileid of the underlying directory.
      </t>
      <t>
        UNIX-based operating environments connect a file system into
        the namespace by connecting (mounting) the file system onto
        the existing file object (the mount point, usually a
        directory) of an existing file system. When the mount point's
        parent directory is read via an API such as readdir()
        <xref target="readdir_api"/>, the return results are
        directory entries, each with a component name and
        a fileid. The fileid of the mount point's directory entry will
        be different from the fileid that the stat() <xref target="stat"/>
        system call returns. The stat() system call is
        returning the fileid of the root of the mounted file system,
        whereas readdir() is returning the fileid that stat() would have
        returned before any file systems were mounted on the mount point.
      </t>
      <t>
        Unlike NFSv3, NFSv4.0 allows a client's LOOKUP
        request to cross other file systems. The client detects the
        file system crossing whenever the filehandle argument of
        LOOKUP has an fsid attribute different from that of the
        filehandle returned by LOOKUP. A UNIX-based client will
        consider this a "mount point crossing".  UNIX has a legacy
        scheme for allowing a process to determine its current working
        directory. This relies on readdir() of a mount point's parent
        and stat() of the mount point returning fileids as previously
        described.  The mounted_on_fileid attribute corresponds to the
        fileid that readdir() would have returned, as described
        previously.
      </t>
      <t>
        While the NFSv4.0 client could simply fabricate a fileid
        corresponding to what mounted_on_fileid provides (and if the
        server does not support mounted_on_fileid, the client has no
        choice), there is a risk that the client will generate a
        fileid that conflicts with one that is already assigned to
        another object in the file system. Instead, if the server can
        provide the mounted_on_fileid, the potential for client
        operational problems in this area is eliminated.
      </t>
      <t>
        If the server detects that there is nothing mounted on top of
        the target file object, then the value for mounted_on_fileid
        that it returns is the same as that of the fileid attribute.
      </t>
      <t>
        The mounted_on_fileid attribute is RECOMMENDED, so the server
        SHOULD provide it if possible, and for a UNIX-based server,
        this is straightforward. Usually, mounted_on_fileid will be
        requested during a READDIR operation, in which case it is
        trivial (at least for UNIX-based servers) to return
        mounted_on_fileid since it is equal to the fileid of a
        directory entry returned by readdir().  If mounted_on_fileid
        is requested in a GETATTR operation, the server should obey an
        invariant that has it returning a value that is equal to the
        file object's entry in the object's parent directory,
        i.e., what readdir() would have returned.  Some operating
        environments allow a series of two or more file systems to be
        mounted onto a single mount point. In this case, for the
        server to obey the aforementioned invariant, it will need to
        find the base mount point, and not the intermediate mount
        points.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_no_trunc"
             title="Attribute 34: no_trunc">
      <t>
        If this attribute is TRUE, then if the client uses a filename
        longer than name_max, an error will be returned instead of the
        name being truncated.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_numlinks"
             title="Attribute 35: numlinks">
      <t>
        Number of hard links to this object.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_owner"
             title="Attribute 36: owner">
      <t>
        The string name of the owner of this object.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_owner_group"
             title="Attribute 37: owner_group">
      <t>
        The string name of the group ownership of this object.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_quota_avail_hard"
             title="Attribute 38: quota_avail_hard">
      <t anchor="quota_avail_hard">
        The value in bytes that represents the amount of additional
        disk space beyond the current allocation that can be allocated
        to this file or directory before further allocations will be
        refused.  It is understood that this space may be consumed by
        allocations to other files or directories.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_quota_avail_soft"
             title="Attribute 39: quota_avail_soft">
      <t anchor="quota_avail_soft">
        The value in bytes that represents the amount of additional
        disk space that can be allocated to this file or directory
        before the user may reasonably be warned.  It is understood
        that this space may be consumed by allocations to other files
        or directories, though there may exist server-side rules as
        to which other files or directories.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_quota_used"
             title="Attribute 40: quota_used">
      <t anchor="quota_used">
        The value in bytes that represents the amount of disk
        space used by this file or directory and possibly a
        number of other similar files or directories, where the
        set of "similar" meets at least the criterion that
        allocating space to any file or directory in the set
        will reduce the "quota_avail_hard" of every other file
        or directory in the set.
      <vspace blankLines='1' />
        Note that there may be a number of distinct but
        overlapping sets of files or directories for which a
        quota_used value is maintained, e.g., "all files with a
        given owner", "all files with a given group owner", etc.
        The server is at liberty to choose any of those sets when
        providing the content of the quota_used attribute but should do
        so in a repeatable way.  The rule may be configured per
        file system or may be "choose the set with the smallest quota".
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_rawdev"
             title="Attribute 41: rawdev">
      <t>
        Raw device number of file of type NF4BLK or NF4CHR.  The device
        number is split into major and minor numbers.   If the file's type
        attribute is not NF4BLK or NF4CHR, this attribute SHOULD NOT be
        returned, and any value returned SHOULD NOT be considered useful.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_space_avail"
             title="Attribute 42: space_avail">
      <t>
        Disk space in bytes available to this user on the file system
        containing this object -- this should be the smallest
        relevant limit.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_space_free"
             title="Attribute 43: space_free">
      <t>
        Free disk space in bytes on the file system containing this
        object -- this should be the smallest relevant limit.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_space_total"
             title="Attribute 44: space_total">
      <t>
        Total disk space in bytes on the file system containing this object.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_space_used"
             title="Attribute 45: space_used">
      <t>
        Number of file system bytes allocated to this object.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_system"
             title="Attribute 46: system">
      <t>
        TRUE, if this file is a "system" file with respect to the
        Windows operating environment.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_time_access"
             title="Attribute 47: time_access">
      <t>
        Represents the time of last access to the object by a READ
        operation sent to the server.  The notion of what is
        an "access" depends on the server's operating environment and/or the
        server's file system semantics.  For example, for servers obeying
        Portable Operating System Interface (POSIX) semantics, time_access
        would be updated only by the READ and READDIR operations and not any
        of the operations that modify the content of the object 
        <xref target="read_api"/>, <xref target="readdir_api" />,
        <xref target="write_api"/>.  Of course, setting the corresponding
        time_access_set attribute is another way to modify the time_access
        attribute.
      </t>
      <t>
        Whenever the file object resides on a writable file system,
        the server should make its best efforts to record time_access into
        stable storage.  However, to mitigate the performance effects
        of doing so, and most especially whenever the server is
        satisfying the read of the object's content from its cache,
        the server MAY cache access time updates and lazily write them
        to stable storage.  It is also acceptable to give
        administrators of the server the option to disable time_access
        updates.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_time_access_set"
             title="Attribute 48: time_access_set">
      <t>
        Sets the time of last access to the object.  SETATTR use only.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_time_backup"
             title="Attribute 49: time_backup">
      <t>
        The time of last backup of the object.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_time_create"
             title="Attribute 50: time_create">
      <t>
        The time of creation of the object. This attribute does not
        have any relation to the traditional UNIX file attribute
        "ctime" ("change time").
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_time_delta"
             title="Attribute 51: time_delta">
      <t>
        Smallest useful server time granularity.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_time_metadata"
             title="Attribute 52: time_metadata">
      <t>
        The time of last metadata modification of the object.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_time_modify"
             title="Attribute 53: time_modify">
      <t>
        The time of last modification to the object.
      </t>
    </section>

    <section toc="exclude" anchor="attrdef_time_modify_set"
             title="Attribute 54: time_modify_set">
      <t>
        Sets the time of last modification to the object.  SETATTR use only.
      </t>
    </section>

   </section>

  </section>

  <section anchor="sec:fattr:owner_group" 
           title="Interpreting owner and owner_group">
    <t>
      The RECOMMENDED attributes "owner" and "owner_group" (and also users
      and groups used as values of the who field within nfs4ace structures
      used in the acl attribute) are represented in the form of UTF-8
      strings.  This format avoids the use of a representation that is tied
      to a particular underlying implementation at the client or server.
      Note that Section 6.1 of <xref target="RFC2624" /> provides additional
      rationale.  It is expected that the client and server will have
      their own local representation of owners and groups that is used
      for local storage or presentation to the application via APIs that
      expect such a representation.  Therefore, the protocol requires
      that when these attributes are transferred between the client and
      server, the local representation is translated to a string of the
      form "identifier@dns_domain".  This allows clients and servers that
      do not use the same local representation to effectively interoperate
      since they both use a common syntax that can be interpreted by both.
    </t>
    <t>
      Similarly, security principals may be represented in different
      ways by different security mechanisms.  Servers normally
      translate these representations into a common format,
      generally that used by local storage, to serve as a means of
      identifying the users corresponding to these security
      principals.  When these local identifiers are translated to
      the form of the owner attribute, associated with files created
      by such principals, they identify, in a common format, the
      users associated with each corresponding set of security
      principals.
    </t>
    <t>
      The translation used to interpret owner and group strings is
      not specified as part of the protocol.  This allows various
      solutions to be employed.  For example, a local translation
      table may be consulted that maps a numeric identifier to the
      user@dns_domain syntax.  A name service may also be used to
      accomplish the translation.  A server may provide a more
      general service, not limited by any particular translation
      (which would only translate a limited set of possible strings)
      by storing the owner and owner_group attributes in local
      storage without any translation, or it may augment a
      translation method by storing the entire string for attributes
      for which no translation is available while using the local
      representation for those cases in which a translation is
      available.
    </t>
    <t>
      Servers that do not provide support for all possible values of user
      and group strings SHOULD return an error (NFS4ERR_BADOWNER) when a
      string is presented that has no translation, as the value to be set
      for a SETATTR of the owner or owner_group attributes or as part of
      the value of the acl attribute.  When a server does accept a user
      or group string as valid on a SETATTR, it is promising to return
      that same string (see below) when a corresponding GETATTR
      is done, as long as there has been no further change in the
      corresponding attribute before the GETATTR. For some
      internationalization-related exceptions where this is not possible,
      see below.  Configuration changes (including changes from the mapping
      of the string to the local representation) and ill-constructed name
      translations (those that contain aliasing) may make that promise
      impossible to honor.  Servers should make appropriate efforts to
      avoid a situation in which these attributes have their values changed
      when no real change to either ownership or acls has occurred.
    </t>
    <t>
      The "dns_domain" portion of the owner string is meant to be a 
      DNS domain name -- for example, "user@example.org".  Servers
      should accept as valid a set of users for at least one domain.
      A server may treat other domains as having no valid
      translations.  A more general service is provided when a
      server is capable of accepting users for multiple domains, or
      for all domains, subject to security constraints.
    </t>
    <t>
      As an implementation guide, both clients and servers may
      provide a means to configure the "dns_domain" portion of the
      owner string. For example, the DNS domain name of
      the host running the NFS server might be
      "lab.example.org", but the user names are defined in
      "example.org". In the absence of such a configuration,
      or as a default, the current DNS domain name of the server
      should be the value used for the "dns_domain".
    </t>
    <t>
      As mentioned above, it is desirable that a server, when accepting
      a string of the form "user@domain" or "group@domain" in an
      attribute, return this same string when that corresponding
      attribute is fetched.  Internationalization issues make this
      impossible under certain circumstances, and the client needs
      to take note of these. See <xref target="sec:i18n" /> for a
      detailed discussion of these issues.
    </t>
    <t>
      In the case where there is no translation available to the
      client or server, the attribute value will be constructed
      without the "@".  Therefore, the absence of the "@" from the
      owner or owner_group attribute signifies that no translation
      was available at the sender and that the receiver of the
      attribute should not use that string as a basis for
      translation into its own internal format.  Even though the
      attribute value cannot be translated, it may still be useful.
      In the case of a client, the attribute string may be used for
      local display of ownership.
    </t>
    <t>
      To provide a greater degree of compatibility with NFSv3, which
      identified users and groups by 32-bit unsigned user identifiers
      and group identifiers, owner and group strings that consist of
      ASCII-encoded decimal numeric values with no leading
      zeros can be given a special interpretation by clients and
      servers that choose to provide such support.  The receiver
      may treat such a user or group string as representing the same
      user as would be represented by an NFSv3 uid or gid having the
      corresponding numeric value.
    </t>
    <t>
      A server SHOULD reject such a numeric value if the security
      mechanism is using Kerberos. That is, in such a scenario, the client
      will already need to form "user@domain" strings. For any
      other security mechanism, the server SHOULD accept such
      numeric values. As an implementation note, the server could
      make such an acceptance be configurable. If the server does
      not support numeric values or if it is configured off, then
      it MUST return an NFS4ERR_BADOWNER error. If the security
      mechanism is using Kerberos and the client attempts to use the
      special form, then the server SHOULD return an NFS4ERR_BADOWNER
      error when there is a valid translation for the user or owner
      designated in this way.  In that case, the client must use
      the appropriate user@domain string and not the special form
      for compatibility.
    </t>
    <t>
      The client MUST always accept numeric values if the security
      mechanism is not RPCSEC_GSS.  A client can determine if a server
      supports numeric identifiers by first attempting to provide a
      numeric identifier. If this attempt is rejected with an
      NFS4ERR_BADOWNER error, then the client should only use named
      identifiers of the form "user@dns_domain".
    </t>
    <t>
      The owner string "nobody" may be used to designate an
      anonymous user, which will be associated with a file created
      by a security principal that cannot be mapped through normal
      means to the owner attribute.
    </t>
  </section>

  <section anchor="character_case_attributes" title="Character Case Attributes">
    <t>
      With respect to the case_insensitive and case_preserving attributes,
      case-insensitive comparisons of Unicode characters SHOULD use Unicode
      Default Case Folding as defined in Chapter 3 of the Unicode Standard
      <xref target="UNICODE" /> and MAY override that behavior for
      specific selected characters with the case folding defined in
      the SpecialCasing.txt <xref target="SPECIALCASING" /> file; see
      Section 3.13 of the Unicode Standard.
    </t>

    <t>
      The SpecialCasing.txt file replaces the Default Case Folding with
      locale- and context-dependent case folding for specific situations.
      An example of locale- and context-dependent case folding is that
      LATIN CAPITAL LETTER I ("I", U+0049) is default case folded to
      LATIN SMALL LETTER I ("i", U+0069). However, several languages
      (e.g., Turkish) treat an "I" character with a dot as a different
      letter than an "I" character without a dot; therefore, in such
      languages, unless an I is before a dot_above, the "I" (U+0049)
      character should be case folded to a different character,
      LATIN SMALL LETTER DOTLESS I (U+0131).
    </t>

    <t>
      The <xref target="UNICODE" /> and
      <xref target="SPECIALCASING" /> references in this RFC 
      are for version 7.0.0 of the Unicode standard, as that was
      the latest version of Unicode when this RFC was published.
      Implementations SHOULD always use the latest version of Unicode
      (&lt;http://www.unicode.org/versions/latest/&gt;).
    </t>

  </section>
</section>

<section title="Access Control Attributes" anchor="sec:acl">
    <t>
        Access Control Lists (ACLs) are file attributes that specify
        fine-grained access control. This section covers the
        &quot;acl&quot;, &quot;aclsupport&quot;, and &quot;mode&quot;
        file attributes, and their interactions.  Note that file
        attributes may apply to any file system object.
    </t>

    <section title="Goals">
      <t>
        ACLs and modes represent two well-established models for
        specifying permissions. This section specifies requirements
        that attempt to meet the following goals:

        <list style="symbols">
          <t>
            If a server supports the mode attribute, it should provide
            reasonable semantics to clients that only set and retrieve
            the mode attribute.
          </t>
          <t>
            If a server supports ACL attributes, it should provide
            reasonable semantics to clients that only set and retrieve
            those attributes.
          </t>
          <t>
            On servers that support the mode attribute, if ACL
            attributes have never been set on an object, via
            inheritance or explicitly, the behavior should be
            traditional UNIX-like behavior.
          </t>
          <t>
            On servers that support the mode attribute, if the ACL
            attributes have been previously set on an object, either
            explicitly or via inheritance:
            <list>
              <t>
                Setting only the mode attribute should effectively
                control the traditional UNIX-like permissions of read,
                write, and execute on owner, owner_group, and other.
              </t>
              <t>
                Setting only the mode attribute should provide
                reasonable security. For example, setting a mode of
                000 should be enough to ensure that future opens for
                read or write by any principal fail, regardless of a
                previously existing or inherited ACL.
              </t>
            </list>
          </t>
          <t>
            When a mode attribute is set on an object, the ACL
            attributes may need to be modified so as to not conflict
            with the new mode. In such cases, it is desirable that the
            ACL keep as much information as possible. This includes
            information about inheritance, AUDIT and ALARM
            access control entries (ACEs), and permissions granted and
            denied that do not conflict with the new mode.
          </t>
        </list>
      </t>
    </section>

    <section title="File Attributes Discussion">
      <t>
        Support for each of the ACL attributes is RECOMMENDED and not
        required, since file systems accessed using NFSv4 might not
        support ACLs.
      </t>

      <section anchor="attrdef_acl"
         title="Attribute 12: acl">
        <t>
          The NFSv4.0 ACL attribute contains an array of ACEs that are
          associated with the file system object.  Although the client
          can read and write the acl attribute, the server is
          responsible for using the ACL to perform access control. The
          client can use the OPEN or ACCESS operations to check access
          without modifying or reading data or metadata.
        </t>

        <t>
          The NFS ACE structure is defined as follows:
        </t>
<figure>
 <artwork>
typedef uint32_t        acetype4;
 </artwork>
</figure>
<figure>
 <artwork>
typedef uint32_t        aceflag4;
 </artwork>
</figure>
<figure>
 <artwork>
typedef uint32_t        acemask4;
 </artwork>
</figure>
<figure>
 <artwork>
struct nfsace4 {
        acetype4                type;
        aceflag4                flag;
        acemask4                access_mask;
        utf8str_mixed           who;
};
 </artwork>
</figure>

        <t>
          To determine if a request succeeds, the server processes
          each nfsace4 entry in order.  Only ACEs that have a "who"
          that matches the requester are considered.  Each ACE is
          processed until all of the bits of the requester's access
          have been ALLOWED.  Once a bit (see below) has been ALLOWED
          by an ACCESS_ALLOWED_ACE, it is no longer considered in the
          processing of later ACEs.  If an ACCESS_DENIED_ACE is
          encountered where the requester's access still has unALLOWED
          bits in common with the "access_mask" of the ACE, the
          request is denied.  When the ACL is fully processed, if
          there are bits in the requester's mask that have not been
          ALLOWED or DENIED, access is denied.
        </t>
        <t>
          Unlike the ALLOW and DENY ACE types, the ALARM and AUDIT ACE
          types do not affect a requester's access and instead are
          for triggering events as a result of a requester's access
          attempt.  Therefore, AUDIT and ALARM ACEs are processed only
          after processing ALLOW and DENY ACEs.
        </t>
        <t>
          The NFSv4.0 ACL model is quite rich. Some server
          platforms may provide access control functionality that goes
          beyond the UNIX-style mode attribute but that is not as
          rich as the NFS ACL model.  So that users can take advantage
          of this more limited functionality, the server may support
          the acl attributes by mapping between its ACL model and the
          NFSv4.0 ACL model.  Servers must ensure that the ACL
          they actually store or enforce is at least as strict as the
          NFSv4 ACL that was set.  It is tempting to accomplish this
          by rejecting any ACL that falls outside the small set that
          can be represented accurately.  However, such an approach
          can render ACLs unusable without special client-side
          knowledge of the server's mapping, which defeats the purpose
          of having a common NFSv4 ACL protocol.  Therefore, servers
          should accept every ACL that they can without compromising
          security.  To help accomplish this, servers may make a
          special exception, in the case of unsupported permission
          bits, to the rule that bits not ALLOWED or DENIED by an ACL
          must be denied.  For example, a UNIX-style server might
          choose to silently allow read attribute permissions even
          though an ACL does not explicitly allow those permissions.
          (An ACL that explicitly denies permission to read attributes
          should still result in a denial.)
        </t>
        <t>
          The situation is complicated by the fact that a server may
          have multiple modules that enforce ACLs. For example, the
          enforcement for NFSv4.0 access may be different from,
          but not weaker than, the enforcement for local access, and
          both may be different from the enforcement for access
          through other protocols such as Server Message Block (SMB)
          <xref target='MS-SMB' />.  So it may be useful for
          a server to accept an ACL even if not all of its modules are
          able to support it.
        </t>

        <t>
          The guiding principle with regard to NFSv4 access is that
          the server must not accept ACLs that give an appearance
          of more restricted access to a file than what is actually
          enforced.
        </t>

        <section title="ACE Type">
          <t>
            The constants used for the type field (acetype4) are as
            follows:
          </t>

<figure>
 <artwork>
const ACE4_ACCESS_ALLOWED_ACE_TYPE      = 0x00000000;
const ACE4_ACCESS_DENIED_ACE_TYPE       = 0x00000001;
const ACE4_SYSTEM_AUDIT_ACE_TYPE        = 0x00000002;
const ACE4_SYSTEM_ALARM_ACE_TYPE        = 0x00000003;
 </artwork>
</figure>
          <t>
            All four bit types are permitted in the acl attribute.
          </t>

          <?rfc compact="no"?>
          <texttable>
            <ttcol>Value</ttcol>
            <ttcol>Abbreviation</ttcol>
            <ttcol>Description</ttcol>
            <c>ACE4_ACCESS_ALLOWED_ACE_TYPE</c>
            <c>ALLOW</c>
            <c>
              Explicitly grants the access defined in acemask4 to
              the file or directory.
            </c>
            <c>ACE4_ACCESS_DENIED_ACE_TYPE</c>
            <c>DENY</c>
            <c>
              Explicitly denies the access defined in acemask4 to
              the file or directory.
            </c>
            <c>ACE4_SYSTEM_AUDIT_ACE_TYPE</c>
            <c>AUDIT</c>
            <c>
              LOG (in a system-dependent way) any access attempt to
              a file or directory that uses any of the access
              methods specified in acemask4.
            </c>
            <c>ACE4_SYSTEM_ALARM_ACE_TYPE</c>
            <c>ALARM</c>
            <c>
              Generate a system ALARM (system dependent) when any
              access attempt is made to a file or directory for the
              access methods specified in acemask4.
            </c>
            <postamble>
              The &quot;Abbreviation&quot; column denotes how the
              types will be referred to throughout the rest of this
              section.
            </postamble>
          </texttable>
        <?rfc compact="yes"?>
        </section>
  <section anchor="attrdef_aclsupport"
       title="Attribute 13: aclsupport">
          <t>
            A server need not support all of the above ACE types.
            This attribute indicates which ACE types are supported for
            the current file system.  The bitmask constants used to
            represent the above definitions within the aclsupport
            attribute are as follows:
          </t>

<figure>
 <artwork>
const ACL4_SUPPORT_ALLOW_ACL    = 0x00000001;
const ACL4_SUPPORT_DENY_ACL     = 0x00000002;
const ACL4_SUPPORT_AUDIT_ACL    = 0x00000004;
const ACL4_SUPPORT_ALARM_ACL    = 0x00000008;
 </artwork>
</figure>
          <t>
            Servers that support either the ALLOW or DENY ACE type
            SHOULD support both ALLOW and DENY ACE types.
          </t>
          <t>
            Clients should not attempt to set an ACE unless the server
            claims support for that ACE type. If the server receives a
            request to set an ACE that it cannot store, it MUST reject
            the request with NFS4ERR_ATTRNOTSUPP. If the server
            receives a request to set an ACE that it can store but
            cannot enforce, the server SHOULD reject the request with
            NFS4ERR_ATTRNOTSUPP.
          </t>
        </section>
        <section anchor="acemask" title="ACE Access Mask">
          <t>
            The bitmask constants used for the access mask field
            are as follows:
          </t>

          <t>
<figure>
 <artwork>
const ACE4_READ_DATA            = 0x00000001;
const ACE4_LIST_DIRECTORY       = 0x00000001;
const ACE4_WRITE_DATA           = 0x00000002;
const ACE4_ADD_FILE             = 0x00000002;
const ACE4_APPEND_DATA          = 0x00000004;
const ACE4_ADD_SUBDIRECTORY     = 0x00000004;
const ACE4_READ_NAMED_ATTRS     = 0x00000008;
const ACE4_WRITE_NAMED_ATTRS    = 0x00000010;
const ACE4_EXECUTE              = 0x00000020;
const ACE4_DELETE_CHILD         = 0x00000040;
const ACE4_READ_ATTRIBUTES      = 0x00000080;
const ACE4_WRITE_ATTRIBUTES     = 0x00000100;

const ACE4_DELETE               = 0x00010000;
const ACE4_READ_ACL             = 0x00020000;
const ACE4_WRITE_ACL            = 0x00040000;
const ACE4_WRITE_OWNER          = 0x00080000;
const ACE4_SYNCHRONIZE          = 0x00100000;
 </artwork>
</figure>
          </t>

          <t>
            Note that some masks have coincident values -- for
            example, ACE4_READ_DATA and ACE4_LIST_DIRECTORY.
            The mask entries ACE4_LIST_DIRECTORY,
            ACE4_ADD_FILE, and ACE4_ADD_SUBDIRECTORY are
            intended to be used with directory objects,
            while ACE4_READ_DATA, ACE4_WRITE_DATA, and
            ACE4_APPEND_DATA are intended to be used with
            non-directory objects.
          </t>

          <section title="Discussion of Mask Attributes">
      <t>
        <list style="hanging">
    <t hangText="ACE4_READ_DATA">
      <list style="hanging">
        <t hangText="Operation(s) affected:">
          <list style="hanging">
      <t hangText="READ" />
      <t hangText="OPEN" />
          </list>
        </t>
        <t hangText="Discussion:">
          <vspace blankLines='1' />
          Permission to read the data of the file.
          <vspace blankLines='1' />
          Servers SHOULD allow a user the ability to read the data
          of the file when only the ACE4_EXECUTE access mask bit is
          set.
        </t>
      </list>
    </t>

    <t hangText="ACE4_LIST_DIRECTORY">
      <list style="hanging">
        <t hangText="Operation(s) affected:">
          <list style="hanging">
      <t hangText="READDIR" />
          </list>
        </t>
        <t hangText="Discussion:">
          <vspace blankLines='1' />
          Permission to list the contents of a directory.
        </t>
      </list>
    </t>

    <t hangText="ACE4_WRITE_DATA">
      <list style="hanging">
        <t hangText="Operation(s) affected:">
          <list style="hanging">
      <t hangText="WRITE" />
      <t hangText="OPEN" />
      <t hangText="SETATTR of size" />
          </list>
        </t>
        <t hangText="Discussion:">
          <vspace blankLines='1' />
          Permission to modify a file's data.
        </t>
      </list>
    </t>

    <t hangText="ACE4_ADD_FILE">
      <list style="hanging">
        <t hangText="Operation(s) affected:">
          <list style="hanging">
      <t hangText="CREATE" />
      <t hangText="LINK" />
      <t hangText="OPEN" />
      <t hangText="RENAME" />
          </list>
        </t>
        <t hangText="Discussion:">
          <vspace blankLines='1' />
          Permission to add a new file in a directory.
          The CREATE operation is affected when nfs_ftype4
          is NF4LNK, NF4BLK, NF4CHR, NF4SOCK, or
          NF4FIFO. (NF4DIR is not listed because it is
          covered by ACE4_ADD_SUBDIRECTORY.) OPEN is
          affected when used to create a regular file.
          LINK and RENAME are always affected.
        </t>
      </list>
    </t>

    <t hangText="ACE4_APPEND_DATA">
      <list style="hanging">
        <t hangText="Operation(s) affected:">
          <list style="hanging">
      <t hangText="WRITE" />
      <t hangText="OPEN" />
      <t hangText="SETATTR of size" />
          </list>
        </t>
        <t hangText="Discussion:">
          <vspace blankLines='1' />
          The ability to modify a file's data, but only
          starting at EOF.  This allows for the notion of
          append-only files, by allowing ACE4_APPEND_DATA
          and denying ACE4_WRITE_DATA to the same user or
          group.  If a file has an ACL such as the one
          described above and a WRITE request is made for
          somewhere other than EOF, the server SHOULD
          return NFS4ERR_ACCESS.
        </t>
      </list>
    </t>

    <t hangText="ACE4_ADD_SUBDIRECTORY">
      <list style="hanging">
        <t hangText="Operation(s) affected:">
          <list style="hanging">
      <t hangText="CREATE" />
      <t hangText="RENAME" />
          </list>
        </t>
        <t hangText="Discussion:">
          <vspace blankLines='1' />
          Permission to create a subdirectory in a
          directory.  The CREATE operation is affected
          when nfs_ftype4 is NF4DIR.  The RENAME operation
          is always affected.
        </t>
      </list>
    </t>

    <t hangText="ACE4_READ_NAMED_ATTRS">
      <list style="hanging">
        <t hangText="Operation(s) affected:">
          <list style="hanging">
      <t hangText="OPENATTR" />
          </list>
        </t>
        <t hangText="Discussion:">
          <vspace blankLines='1' />
          Permission to read the named attributes of a
          file or to look up the named attributes
          directory.  OPENATTR is affected when it is not
          used to create a named attribute directory.
          This is when 1) createdir is TRUE but a named
          attribute directory already exists or 2)
          createdir is FALSE.
        </t>
      </list>
    </t>

    <t hangText="ACE4_WRITE_NAMED_ATTRS">
      <list style="hanging">
        <t hangText="Operation(s) affected:">
          <list style="hanging">
      <t hangText="OPENATTR" />
          </list>
        </t>
        <t hangText="Discussion:">
          <vspace blankLines='1' />
          Permission to write the named attributes of a
          file or to create a named attribute directory.
          OPENATTR is affected when it is used to create a
          named attribute directory.  This is when
          createdir is TRUE and no named attribute
          directory exists.  The ability to check whether
          or not a named attribute directory exists
          depends on the ability to look it up; therefore,
          users also need the ACE4_READ_NAMED_ATTRS
          permission in order to create a named attribute
          directory.
        </t>
      </list>
    </t>

    <t hangText="ACE4_EXECUTE">
      <list style="hanging">
        <t hangText="Operation(s) affected:">
          <list style="hanging">
      <t hangText="READ" />
          </list>
        </t>
        <t hangText="Discussion:">
          <vspace blankLines='1' />
          Permission to execute a file.
          <vspace blankLines='1' />
          Servers SHOULD allow a
          user the ability to read the data of the file
          when only the ACE4_EXECUTE access mask bit is
          set.  This is because there is no way to
          execute a file without reading the contents.
          Though a server may treat ACE4_EXECUTE and
          ACE4_READ_DATA bits identically when deciding to
          permit a READ operation, it SHOULD still allow
          the two bits to be set independently in ACLs
          and MUST distinguish between them when replying
          to ACCESS operations.  In particular, servers
          SHOULD NOT silently turn on one of the two bits
          when the other is set, as that would make it
          impossible for the client to correctly enforce
          the distinction between read and execute
          permissions.
          <vspace blankLines='1' />
          As an example, following a SETATTR of the following ACL:
          <vspace blankLines='1' />
                      nfsuser:ACE4_EXECUTE:ALLOW
          <vspace blankLines='1' />
          A subsequent GETATTR of ACL for that file SHOULD return:
          <vspace blankLines='1' />
                      nfsuser:ACE4_EXECUTE:ALLOW
          <vspace blankLines='1' />
          Rather than:
          <vspace blankLines='1' />
                      nfsuser:ACE4_EXECUTE/ACE4_READ_DATA:ALLOW
        </t>
      </list>
    </t>

    <t hangText="ACE4_EXECUTE">
      <list style="hanging">
        <t hangText="Operation(s) affected:">
          <list style="hanging">
      <t hangText="LOOKUP" />
      <t hangText="OPEN" />
      <t hangText="REMOVE" />
      <t hangText="RENAME" />
      <t hangText="LINK" />
      <t hangText="CREATE" />
          </list>
        </t>
        <t hangText="Discussion:">
          <vspace blankLines='1' />
          Permission to traverse/search a directory.
        </t>
      </list>
    </t>

    <t hangText="ACE4_DELETE_CHILD">
      <list style="hanging">
        <t hangText="Operation(s) affected:">
          <list style="hanging">
      <t hangText="REMOVE" />
      <t hangText="RENAME" />
          </list>
        </t>
        <t hangText="Discussion:">
          <vspace blankLines='1' />
          Permission to delete a file or directory within
          a directory.

          See <xref
          target="delete-delete_child"/>
          for information on how ACE4_DELETE and
          ACE4_DELETE_CHILD interact.

        </t>
      </list>
    </t>

    <t hangText="ACE4_READ_ATTRIBUTES">
      <list style="hanging">
        <t hangText="Operation(s) affected:">
          <list style="hanging">
      <t hangText="GETATTR of file system object attributes" />
      <t hangText="VERIFY" />
      <t hangText="NVERIFY" />
      <t hangText="READDIR" />
          </list>
        </t>
        <t hangText="Discussion:">
          <vspace blankLines='1' />
          The ability to read basic attributes (non-ACLs)
          of a file.  On a UNIX system, basic attributes
          can be thought of as the stat-level attributes.
          Allowing this access mask bit would mean the
          entity can execute "ls -l" and stat.  If a
          READDIR operation requests attributes, this mask
          must be allowed for the READDIR to succeed.
        </t>
      </list>
    </t>

    <t hangText="ACE4_WRITE_ATTRIBUTES">
      <list style="hanging">
        <t hangText="Operation(s) affected:">
          <list style="hanging">
      <t hangText="SETATTR of time_access_set, time_backup, time_create," />
  <?rfc subcompact="yes"?>
      <t hangText="time_modify_set, mimetype, hidden, and system" />
  <?rfc subcompact="no"?>
          </list>

        </t>
        <t hangText="Discussion:">
          <vspace blankLines='1' />
          Permission to change the times associated with a
          file or directory to an arbitrary value.  Also,
          permission to change the mimetype, hidden and
          system attributes.  A user having
          ACE4_WRITE_DATA or ACE4_WRITE_ATTRIBUTES will be
          allowed to set the times associated with a file
          to the current server time.
        </t>
      </list>
    </t>

    <t hangText="ACE4_DELETE">
      <list style="hanging">
        <t hangText="Operation(s) affected:">
          <list style="hanging">
      <t hangText="REMOVE" />
          </list>
        </t>
        <t hangText="Discussion:">
          <vspace blankLines='1' />

          Permission to delete the file or directory.

          See <xref target="delete-delete_child"/>
          for information on ACE4_DELETE and
          ACE4_DELETE_CHILD interact.

        </t>
      </list>
    </t>

    <t hangText="ACE4_READ_ACL">
      <list style="hanging">
        <t hangText="Operation(s) affected:">
          <list style="hanging">
      <t hangText="GETATTR of acl" />
      <t hangText="NVERIFY" />
      <t hangText="VERIFY" />
          </list>
        </t>
        <t hangText="Discussion:">
          <vspace blankLines='1' />
          Permission to read the ACL.
        </t>
      </list>
    </t>

    <t hangText="ACE4_WRITE_ACL">
      <list style="hanging">
        <t hangText="Operation(s) affected:">
          <list style="hanging">
      <t hangText="SETATTR of acl and mode" />
          </list>
        </t>
        <t hangText="Discussion:">
          <vspace blankLines='1' />
          Permission to write the acl and mode attributes.
        </t>
      </list>
    </t>

    <t hangText="ACE4_WRITE_OWNER">
      <list style="hanging">
        <t hangText="Operation(s) affected:">
          <list style="hanging">
      <t hangText="SETATTR of owner and owner_group" />
          </list>
        </t>
        <t hangText="Discussion:">
          <vspace blankLines='1' />
          Permission to write the owner and owner_group
          attributes.  On UNIX systems, this is the
          ability to execute chown() and chgrp().
        </t>
      </list>
    </t>

    <t hangText="ACE4_SYNCHRONIZE">
      <list style="hanging">
        <t hangText="Operation(s) affected:">
          <list style="hanging">
            <t hangText="NONE" />
              </list>
                </t>
                  <t hangText='Discussion:'><vspace blankLines="1"/>
                    Permission to use the file object as a synchronization
                    primitive for interprocess communication.  This permission is
                    not enforced or interpreted by the NFSv4.0 server on behalf of
                    the client.
                    <vspace blankLines="1"/>
                    Typically, the ACE4_SYNCHRONIZE permission is only meaningful
                    on local file systems, i.e., file systems not accessed via
                    NFSv4.0.  The reason that the permission bit exists is that
                    some operating environments, such as Windows, use
                    ACE4_SYNCHRONIZE.
                    <vspace blankLines="1"/>
                    For example, if a client copies a file that has
                    ACE4_SYNCHRONIZE set from a local file system to an NFSv4.0
                    server, and then later copies the file from the NFSv4.0 server
                    to a local file system, it is likely that if ACE4_SYNCHRONIZE
                    was set in the original file, the client will want it set in
                    the second copy.  The first copy will not have the permission
                    set unless the NFSv4.0 server has the means to set the
                    ACE4_SYNCHRONIZE bit.  The second copy will not have the
                    permission set unless the NFSv4.0 server has the means to
                    retrieve the ACE4_SYNCHRONIZE bit.
                  </t>
                </list>
              </t>
            </list>
            </t>

            <t>
              Server implementations need not provide the granularity
              of control that is implied by this list of masks. For
              example, POSIX-based systems might not distinguish
              ACE4_APPEND_DATA (the ability to append to a file) from
              ACE4_WRITE_DATA (the ability to modify existing
              contents); both masks would be tied to a single "write"
              permission. When such a server returns attributes to the
              client, it would show both ACE4_APPEND_DATA and
              ACE4_WRITE_DATA if and only if the write permission is
              enabled.
            </t>

            <t>
              If a server receives a SETATTR request that it cannot
              accurately implement, it should err in the direction of
              more restricted access, except in the previously
              discussed cases of execute and read. For example,
              suppose a server cannot distinguish overwriting data
              from appending new data, as described in the previous
              paragraph.  If a client submits an ALLOW ACE where
              ACE4_APPEND_DATA is set but ACE4_WRITE_DATA is not (or
              vice versa), the server should either turn off
              ACE4_APPEND_DATA or reject the request with
              NFS4ERR_ATTRNOTSUPP.
            </t>
          </section>

          <section anchor="delete-delete_child" title="ACE4_DELETE versus ACE4_DELETE_CHILD">
            <t>
              Two access mask bits govern the ability to delete a
              directory entry: ACE4_DELETE on the object
              itself (the "target") and ACE4_DELETE_CHILD on
              the containing directory (the "parent").
            </t>

            <t>
              Many systems also take the "sticky bit" (MODE4_SVTX)
              on a directory to allow unlink only to a user that
              owns either the target or the parent; on some
              such systems, the decision also depends on
              whether the target is writable.
            </t>

            <t>
              Servers SHOULD allow unlink if either ACE4_DELETE
              is permitted on the target or ACE4_DELETE_CHILD is
              permitted on the parent.  (Note that this is
              true even if the parent or target explicitly
              denies the other of these permissions.)
            </t>

            <t>
              If the ACLs in question neither explicitly ALLOW
              nor DENY either of the above, and if MODE4_SVTX is
              not set on the parent, then the server SHOULD allow
              the removal if and only if ACE4_ADD_FILE is permitted.
              In the case where MODE4_SVTX is set, the server
              may also require the remover to own either the parent
              or the target, or may require the target to be
              writable.
            </t>

            <t>
              This allows servers to support something close to
              traditional UNIX-like semantics, with ACE4_ADD_FILE
              taking the place of the write bit.
            </t>

          </section>
        </section>
        <section anchor="aceflag" title="ACE flag">
          <t>
            The bitmask constants used for the flag field are as
            follows:
<figure>
 <artwork>
const ACE4_FILE_INHERIT_ACE             = 0x00000001;
const ACE4_DIRECTORY_INHERIT_ACE        = 0x00000002;
const ACE4_NO_PROPAGATE_INHERIT_ACE     = 0x00000004;
const ACE4_INHERIT_ONLY_ACE             = 0x00000008;
const ACE4_SUCCESSFUL_ACCESS_ACE_FLAG   = 0x00000010;
const ACE4_FAILED_ACCESS_ACE_FLAG       = 0x00000020;
const ACE4_IDENTIFIER_GROUP             = 0x00000040;
 </artwork>
</figure>

            A server need not support any of these flags. If the
            server supports flags that are similar to, but not
            exactly the same as, these flags, the implementation
            may define a mapping between the protocol-defined
            flags and the implementation-defined flags.
          </t>

          <t>
            For example, suppose a client tries to set an ACE with
            ACE4_FILE_INHERIT_ACE set but not
            ACE4_DIRECTORY_INHERIT_ACE. If the server does not
            support any form of ACL inheritance, the server should
            reject the request with NFS4ERR_ATTRNOTSUPP. If the
            server supports a single "inherit ACE" flag that
            applies to both files and directories, the server may
            reject the request (i.e., requiring the client to set
            both the file and directory inheritance flags). The
            server may also accept the request and silently turn
            on the ACE4_DIRECTORY_INHERIT_ACE flag.
          </t>
          <section title="Discussion of Flag Bits">
            <t>
              <list style="hanging">
                <t hangText="ACE4_FILE_INHERIT_ACE">
                  <vspace />
                  Any non-directory file in any
                  subdirectory will get this ACE
                  inherited.
                </t>

                <t hangText="ACE4_DIRECTORY_INHERIT_ACE">
                  <vspace />
                  Can be placed on a directory and indicates
                  that this ACE should be added to each new
                  directory created.
                  <vspace />
                  If this flag is set in an ACE in an ACL
                  attribute to be set on a non-directory
                  file system object, the operation
                  attempting to set the ACL SHOULD fail
                  with NFS4ERR_ATTRNOTSUPP.
                </t>

                <t hangText="ACE4_INHERIT_ONLY_ACE">
                  <vspace />
                  Can be placed on a directory but does not
                  apply to the directory; ALLOW and DENY ACEs
                  with this bit set do not affect access to
                  the directory, and AUDIT and ALARM ACEs
                  with this bit set do not trigger log or
                  alarm events.  Such ACEs only take effect
                  once they are applied (with this bit
                  cleared) to newly created files and
                  directories as specified by the above two
                  flags.
                  <vspace />
                  If this flag is present on an ACE, but
                  neither ACE4_DIRECTORY_INHERIT_ACE nor
                  ACE4_FILE_INHERIT_ACE is present, then
                  an operation attempting to set such an
                  attribute SHOULD fail with
                  NFS4ERR_ATTRNOTSUPP.
                </t>

                <t hangText="ACE4_NO_PROPAGATE_INHERIT_ACE">
                  <vspace />
                  Can be placed on a directory.  This flag
                  tells the server that inheritance of this
                  ACE should stop at newly created child
                  directories.
                </t>

                <t hangText="ACE4_SUCCESSFUL_ACCESS_ACE_FLAG">
                </t>

                <t hangText="ACE4_FAILED_ACCESS_ACE_FLAG">
                  <vspace />
                  The ACE4_SUCCESSFUL_ACCESS_ACE_FLAG
                  (SUCCESS) and ACE4_FAILED_ACCESS_ACE_FLAG
                  (FAILED) flag bits may be set only on
                  ACE4_SYSTEM_AUDIT_ACE_TYPE (AUDIT) and
                  ACE4_SYSTEM_ALARM_ACE_TYPE (ALARM) ACE
                  types. If, during the processing of the
                  file's ACL, the server encounters an AUDIT
                  or ALARM ACE that matches the principal
                  attempting the OPEN, the server notes that
                  fact and notes the presence, if any, of the
                  SUCCESS and FAILED flags encountered in
                  the AUDIT or ALARM ACE. Once the server
                  completes the ACL processing, it then
                  notes if the operation succeeded or
                  failed. If the operation succeeded, and if
                  the SUCCESS flag was set for a matching
                  AUDIT or ALARM ACE, then the appropriate
                  AUDIT or ALARM event occurs. If the
                  operation failed, and if the FAILED flag
                  was set for the matching AUDIT or ALARM
                  ACE, then the appropriate AUDIT or ALARM
                  event occurs.  Either or both of the
                  SUCCESS or FAILED can be set, but if
                  neither is set, the AUDIT or ALARM ACE is
                  not useful.
                </t>

                <t hangText="">
                  The previously described processing
                  applies to ACCESS operations even when
                  they return NFS4_OK.  For the purposes of
                  AUDIT and ALARM, we consider an ACCESS
                  operation to be a "failure" if it fails
                  to return a bit that was requested and
                  supported.
                </t>

                <t hangText="ACE4_IDENTIFIER_GROUP">
                  <vspace />
                  Indicates that the "who" refers to a GROUP
                  as defined under UNIX or a GROUP ACCOUNT
                  as defined under Windows. Clients and
                  servers MUST ignore the
                  ACE4_IDENTIFIER_GROUP flag on ACEs with a
                  who value equal to one of the special
                  identifiers outlined in <xref target="acewho" />.
                </t>
              </list>
            </t>
          </section>
        </section>

        <section title="ACE Who" anchor="acewho">
          <t>
            The who field of an ACE is an identifier that
            specifies the principal or principals to whom the ACE
            applies. It may refer to a user or a group, with the flag
            bit ACE4_IDENTIFIER_GROUP specifying which.
          </t>
          <t>
            There are several special identifiers that need to be
            understood universally, rather than in the context of a
            particular DNS domain. Some of these identifiers cannot be
            understood when an NFS client accesses the server but
            have meaning when a local process accesses the file. The
            ability to display and modify these permissions is
            permitted over NFS, even if none of the access methods on
            the server understand the identifiers.
          </t>
          <texttable anchor="specialwho" title="Special Identifiers">
            <ttcol>Who</ttcol>
            <ttcol>Description</ttcol>
            <c>OWNER</c>
            <c>
              The owner of the file.
            </c>
            <c>GROUP</c>
            <c>
              The group associated with the file.
            </c>
            <c>EVERYONE</c>
            <c>
              The world, including the owner and owning group.
            </c>
            <c>INTERACTIVE</c>
            <c>
              Accessed from an interactive terminal.
            </c>
            <c>NETWORK</c>
            <c>
              Accessed via the network.
            </c>
            <c>DIALUP</c>
            <c>
              Accessed as a dialup user to the server.
            </c>
            <c>BATCH</c>
            <c>
              Accessed from a batch job.
            </c>
            <c>ANONYMOUS</c>
            <c>
              Accessed without any authentication.
            </c>
            <c>AUTHENTICATED</c>
            <c>
              Any authenticated user (opposite of ANONYMOUS).
            </c>
            <c>SERVICE</c>
            <c>
              Access from a system service.
            </c>
          </texttable>
          <t>
            To avoid conflict, these special identifiers are
            distinguished by an appended "@" and should appear in the
            form "xxxx@" (with no domain name after the "@") -- for
            example, ANONYMOUS@.
          </t>
          <t>
            The ACE4_IDENTIFIER_GROUP flag MUST be ignored on
            entries with these special identifiers.  When encoding
            entries with these special identifiers, the
            ACE4_IDENTIFIER_GROUP flag SHOULD be set to zero.
          </t>

          <section title="Discussion of EVERYONE@">
            <t>
              It is important to note that "EVERYONE@" is not
              equivalent to the UNIX "other" entity. This is
              because, by definition, UNIX "other" does not include
              the owner or owning group of a file. "EVERYONE@" means
              literally everyone, including the owner or owning
              group.
            </t>
          </section>
        </section>
      </section>

      <section anchor="attrdef_mode"
         title="Attribute 33: mode">
        <t>
          The NFSv4.0 mode attribute is based on the UNIX mode
          bits. The following bits are defined:
        </t>

<figure>
 <artwork>
const MODE4_SUID = 0x800;  /* set user id on execution */
const MODE4_SGID = 0x400;  /* set group id on execution */
const MODE4_SVTX = 0x200;  /* save text even after use */
const MODE4_RUSR = 0x100;  /* read permission: owner */
const MODE4_WUSR = 0x080;  /* write permission: owner */
const MODE4_XUSR = 0x040;  /* execute permission: owner */
const MODE4_RGRP = 0x020;  /* read permission: group */
const MODE4_WGRP = 0x010;  /* write permission: group */
const MODE4_XGRP = 0x008;  /* execute permission: group */
const MODE4_ROTH = 0x004;  /* read permission: other */
const MODE4_WOTH = 0x002;  /* write permission: other */
const MODE4_XOTH = 0x001;  /* execute permission: other */
 </artwork>
</figure>

        <t>
          Bits MODE4_RUSR, MODE4_WUSR, and MODE4_XUSR apply to the
          principal identified in the owner attribute. Bits MODE4_RGRP,
          MODE4_WGRP, and MODE4_XGRP apply to principals identified in
          the owner_group attribute but who are not identified in the
          owner attribute. Bits MODE4_ROTH, MODE4_WOTH, and MODE4_XOTH
          apply to any principal that does not match that in the owner
          attribute and does not have a group matching that of the
          owner_group attribute.
        </t>
        <t>
          Bits within the mode other than those specified above
          are not defined by this protocol. A server
          MUST NOT return bits other than those defined above in a
          GETATTR or READDIR operation, and it MUST return NFS4ERR_INVAL
          if bits other than those defined above are set in a SETATTR,
          CREATE, OPEN, VERIFY, or NVERIFY operation.
        </t>
      </section>

    </section>

    <section title="Common Methods">
      <t>
        The requirements in this section will be referred to in future
        sections, especially <xref target="aclreqs" />.
      </t>
      <section title="Interpreting an ACL" anchor="useacl">
        <section title="Server Considerations" anchor="serverinterp">
          <t>
            The server uses the algorithm described in
            <xref target="attrdef_acl"/> to determine whether an ACL
            allows access to an object.  However, the ACL may not be
            the sole determiner of access.  For example:
            <list style="symbols">
              <t>
                In the case of a file system exported as read-only,
                the server may deny write permissions even though
                an object's ACL grants it.
              </t>

              <t>
                Server implementations MAY grant ACE4_WRITE_ACL
                and ACE4_READ_ACL permissions to prevent
                a situation from arising in which there is no valid
                way to ever modify the ACL.
              </t>

              <t>
                All servers will allow a user the ability to read
                the data of the file when only the execute
                permission is granted (i.e., if the ACL denies the
                user ACE4_READ_DATA access and allows the user
                ACE4_EXECUTE, the server will allow the user to
                read the data of the file).
              </t>

              <t>
                Many servers have the notion of owner-override, in
                which the owner of the object is allowed to
                override accesses that are denied by the ACL.
                This may be helpful, for example, to allow users
                continued access to open files on which the
                permissions have changed.
              </t>

              <t>
                Many servers have the notion of a
                &quot;superuser&quot; that has privileges beyond
                an ordinary user.  The superuser may be able
                to read or write data or metadata in ways that would
                not be permitted by the ACL.
              </t>
            </list>
          </t>
        </section>

        <section title="Client Considerations" anchor="clientinterp">
          <t>
            Clients SHOULD NOT do their own access checks based on
            their interpretation of the ACL but rather use the OPEN and
            ACCESS operations to do access checks. This allows the
            client to act on the results of having the server
            determine whether or not access should be granted based on
            its interpretation of the ACL.
          </t>

          <t>
            Clients must be aware of situations in which an object's
            ACL will define a certain access even though the server
            will not have adequate information to enforce it.  For
            example, the server has no way of determining whether
            a particular OPEN reflects a user's open for read access
            or is done as part of executing the file in question.
            In such situations, the client needs to do its part in
            the enforcement of access as defined by the ACL.  To
            do this, the client will send the appropriate ACCESS
            operation (or use a cached previous determination) prior
            to servicing the request of the user or application in
            order to determine whether the user or application
            should be granted the access requested.  For examples in
            which the ACL may define accesses that the server does not
            enforce, see <xref target="serverinterp"/>.
          </t>
        </section>
      </section>

      <section title="Computing a mode Attribute from an ACL"
               anchor="computemode">
        <t>
          The following method can be used to calculate the MODE4_R*,
          MODE4_W*, and MODE4_X* bits of a mode attribute, based upon
          an ACL.
        </t>

        <t>
          First, for each of the special identifiers OWNER@, GROUP@, and
          EVERYONE@, evaluate the ACL in order, considering only ALLOW
          and DENY ACEs for the identifier EVERYONE@ and for the
          identifier under consideration.  The result of the evaluation
          will be an NFSv4 ACL mask showing exactly which bits are
          permitted to that identifier.
        </t>

        <t>
          Then translate the calculated mask for OWNER@, GROUP@, and
          EVERYONE@ into mode bits for the user, group, and other,
          respectively, as follows:

          <list style="numbers">
            <t>
              Set the read bit (MODE4_RUSR, MODE4_RGRP, or
              MODE4_ROTH) if and only if ACE4_READ_DATA is set in
              the corresponding mask.
            </t>

            <t>
              Set the write bit (MODE4_WUSR, MODE4_WGRP, or
              MODE4_WOTH) if and only if ACE4_WRITE_DATA and
              ACE4_APPEND_DATA are both set in the corresponding
              mask.
            </t>

            <t>
              Set the execute bit (MODE4_XUSR, MODE4_XGRP, or
              MODE4_XOTH), if and only if ACE4_EXECUTE is set in the
              corresponding mask.
            </t>
          </list>
        </t>
        <section title="Discussion">
          <t>
            Some server implementations also add bits permitted to
            named users and groups to the group bits (MODE4_RGRP,
            MODE4_WGRP, and MODE4_XGRP).
          </t>
          <t>
            Implementations are discouraged from doing this, because
            it has been found to cause confusion for users who see
            members of a file's group denied access that the mode
            bits appear to allow.  (The presence of DENY ACEs may also
            lead to such behavior, but DENY ACEs are expected to be
            more rarely used.)
          </t>
          <t>
            The same user confusion seen when fetching the mode also
            results if setting the mode does not effectively control
            permissions for the owner, group, and other users; this
            motivates some of the requirements that follow.
          </t>
        </section>
      </section>
    </section>

    <section title="Requirements" anchor="aclreqs">
      <t>
        The server that supports both mode and ACL must take care to
        synchronize the MODE4_*USR, MODE4_*GRP, and MODE4_*OTH bits with
        the ACEs that have respective who fields of "OWNER@", "GROUP@",
        and "EVERYONE@" so that the client can see that semantically
        equivalent access permissions exist whether the client asks
        for just the ACL or any of the owner, owner_group, and mode
        attributes.
      </t>
      <t>
        Many requirements refer to <xref
        target="computemode" />,
        but note that the methods have behaviors specified with
        &quot;SHOULD&quot;. This is intentional, to avoid invalidating
        existing implementations that compute the mode according to the
        withdrawn POSIX ACL draft (<xref target='P1003.1e' />), rather than by
        actual permissions on owner, group, and other.
      </t>
      <section title="Setting the mode and/or ACL Attributes"
               anchor="setattr">
        <section title="Setting mode and Not ACL" anchor="setmode">
          <t>
            When any of the nine low-order mode bits
            are changed because the mode
            attribute was set, and no ACL attribute is explicitly
            set, the acl attribute must be modified
            in accordance with the updated value of those bits.
            This must happen even if the value of the low-order bits
            is the same after the mode is set as before.
          </t>
          <t>
            Note that any AUDIT or ALARM ACEs
            are unaffected by changes to the mode.
          </t>
          <t>
            In cases in which the permissions bits are subject to
            change, the acl attribute
            MUST be modified such that the mode computed via the
            method described in <xref target="computemode" />
            yields the low-order nine bits (MODE4_R*, MODE4_W*,
            MODE4_X*) of the mode attribute as modified by the
            change attribute.  The ACL attributes
            SHOULD also be modified such that:
            <list style="numbers">
              <t>
                If MODE4_RGRP is not set, entities explicitly
                listed in the ACL other than OWNER@ and EVERYONE@
                SHOULD NOT be granted ACE4_READ_DATA.
              </t>
              <t>
                If MODE4_WGRP is not set, entities explicitly
                listed in the ACL other than OWNER@ and
                EVERYONE@ SHOULD NOT be granted
                ACE4_WRITE_DATA or ACE4_APPEND_DATA.
              </t>
              <t>
                If MODE4_XGRP is not set, entities explicitly
                listed in the ACL other than OWNER@ and EVERYONE@
                SHOULD NOT be granted ACE4_EXECUTE.
              </t>
            </list>
            Access mask bits other than those listed above, appearing
            in ALLOW ACEs, MAY also be disabled.
          </t>
          <t>
            Note that ACEs with the flag ACE4_INHERIT_ONLY_ACE set do
            not affect the permissions of the ACL itself, nor do ACEs
            of the types AUDIT and ALARM. As such, it is desirable to
            leave these ACEs unmodified when modifying the ACL
            attributes.
          </t>
          <t>
            Also note that the requirement may be met by
            discarding the acl in favor of an ACL
            that represents the mode and only the mode. This is
            permitted, but it is preferable for a server to
            preserve as much of the ACL as possible without
            violating the above requirements. Discarding the
            ACL makes it effectively impossible for a file
            created with a mode attribute to inherit an ACL
            (see <xref target="aclcreate" />).
          </t>
        </section>
        <section title="Setting ACL and Not mode"
                 anchor="settingacl">
          <t>
            When setting the acl and not setting the
            mode attribute, the permission
            bits of the mode need to be derived from the ACL.
            In this case, the ACL attribute SHOULD be set as
            given. The nine low-order bits of the mode
            attribute (MODE4_R*, MODE4_W*, MODE4_X*) MUST be
            modified to match the result of the method described
            in <xref target="computemode" />. The three high-order
            bits of the mode (MODE4_SUID, MODE4_SGID, MODE4_SVTX)
            SHOULD remain unchanged.
          </t>
        </section>
        <section title="Setting Both ACL and mode" anchor="setboth">
          <t>
            When setting both the mode
            and the acl attribute in the
            same operation, the attributes MUST be applied in this
            order: mode, then ACL.  The
            mode-related attribute is set as given,
            then the ACL attribute is set as given, possibly changing
            the final mode, as described above in
            <xref target="settingacl" />.
          </t>
        </section>
      </section>
      <section title="Retrieving the mode and/or ACL Attributes">
        <t>
          This section applies only to servers that support both the
          mode and ACL attributes.
        </t>
        <t>
          Some server implementations may have a concept of
          &quot;objects without ACLs&quot;, meaning that all permissions
          are granted and denied according to the mode attribute, and
          that no ACL attribute is stored for that object. If an ACL
          attribute is requested of such a server, the server SHOULD
          return an ACL that does not conflict with the mode; that is to
          say, the ACL returned SHOULD represent the nine low-order bits
          of the mode attribute (MODE4_R*, MODE4_W*, MODE4_X*) as
          described in <xref target="computemode" />.
        </t>
        <t>
          For other server implementations, the ACL attribute is always
          present for every object. Such servers SHOULD store at least
          the three high-order bits of the mode attribute (MODE4_SUID,
          MODE4_SGID, MODE4_SVTX). The server SHOULD return a mode
          attribute if one is requested, and the low-order nine bits of
          the mode (MODE4_R*, MODE4_W*, MODE4_X*) MUST match the result
          of applying the method in
          <xref target="computemode" /> to the ACL attribute.
        </t>
      </section>
      <section title="Creating New Objects" anchor="aclcreate">
        <t>
          If a server supports any ACL attributes, it may use the ACL
          attributes on the parent directory to compute an initial ACL
          attribute for a newly created object. This will be referred to
          as the inherited ACL within this section. The act of adding
          one or more ACEs to the inherited ACL that are based upon ACEs
          in the parent directory's ACL will be referred to as
          inheriting an ACE within this section.
        </t>
        <t>
          In the presence or absence of the mode and ACL attributes, the
          behavior of CREATE and OPEN SHOULD be:
          <list style="numbers">
            <t>If just the mode is given in the call:
              <vspace blankLines="1" /> In this case, inheritance
              SHOULD take place, but the mode MUST be applied to the
              inherited ACL as described in <xref target="setmode" />,
              thereby modifying the ACL.
            </t>

            <t>If just the ACL is given in the call:
              <vspace blankLines="1" />
              In this case, inheritance SHOULD NOT take place, and
              the ACL as defined in the CREATE or OPEN will be set
              without modification, and the mode modified as in
              <xref target="settingacl" />.
            </t>

            <t>If both mode and ACL are given in the call:
              <vspace blankLines="1" /> In this case, inheritance
              SHOULD NOT take place, and both attributes will be set
              as described in <xref target="setboth" />.
            </t>

            <t>
              If neither mode nor ACL is given in the call:
              <vspace blankLines="1" />
              In the case where an object is being created without
              any initial attributes at all, e.g., an OPEN operation
              with an opentype4 of OPEN4_CREATE and a createmode4 of
              EXCLUSIVE4, inheritance SHOULD NOT take place.
              Instead, the server SHOULD set permissions to deny all
              access to the newly created object. It is expected
              that the appropriate client will set the desired
              attributes in a subsequent SETATTR operation, and the
              server SHOULD allow that operation to succeed,
              regardless of what permissions the object is created
              with. For example, an empty ACL denies all
              permissions, but the server should allow the owner's
              SETATTR to succeed even though WRITE_ACL is implicitly
              denied.
              <vspace blankLines="1" />
              In other cases, inheritance SHOULD take place, and no
              modifications to the ACL will happen. The mode
              attribute, if supported, MUST be as computed via the
              method described in
              <xref target="computemode" />, with the MODE4_SUID,
              MODE4_SGID, and MODE4_SVTX bits clear.
              If no inheritable ACEs exist on the parent directory,
              the rules for creating acl attributes
              are implementation defined.
            </t>
          </list>
        </t>

        <section title="The Inherited ACL" anchor="inheritreq">
          <t>
            If the object being created is not a directory, the
            inherited ACL SHOULD NOT inherit ACEs from the parent
            directory ACL unless the ACE4_FILE_INHERIT_FLAG is set.
          </t>
          <t>
            If the object being created is a directory, the inherited
            ACL should inherit all inheritable ACEs from the parent
            directory, i.e., those that have the ACE4_FILE_INHERIT_ACE or
            ACE4_DIRECTORY_INHERIT_ACE flag set. If the inheritable
            ACE has ACE4_FILE_INHERIT_ACE set, but
            ACE4_DIRECTORY_INHERIT_ACE is clear, the inherited ACE on
            the newly created directory MUST have the
            ACE4_INHERIT_ONLY_ACE flag set to prevent the directory
            from being affected by ACEs meant for non&nbhy;directories.
          </t>
          <t>
            When a new directory is created, the server MAY split
            any inherited ACE that is both inheritable and effective
            (in other words, that has neither ACE4_INHERIT_ONLY_ACE
            nor ACE4_NO_PROPAGATE_INHERIT_ACE set) into two ACEs --
            one with no inheritance flags, and one with
            ACE4_INHERIT_ONLY_ACE set.  This makes it simpler to
            modify the effective permissions on the directory
            without modifying the ACE that is to be inherited to the
            new directory's children.
          </t>
        </section>
      </section>
    </section>
</section>

<section anchor="sec:name_space" title="NFS Server Namespace">

  <section title="Server Exports">

    <t>
      On a UNIX server, the namespace describes all the files reachable by
      pathnames under the root directory or "/".  On a Windows server,
      the namespace constitutes all the files on disks named by mapped
      disk letters.  NFS server administrators rarely make the entire
      server's file system namespace available to NFS clients.  More often,
      portions of the namespace are made available via an "export" feature.
      In previous versions of the NFS protocol, the root filehandle for
      each export is obtained through the MOUNT protocol; the client sends
      a string that identifies an object in the exported namespace,
      and the server returns the root filehandle for it.  The MOUNT
      protocol supports an EXPORTS procedure that will enumerate the
      server's exports.
    </t>

  </section>
  <section title="Browsing Exports">

    <t>
      The NFSv4 protocol provides a root filehandle that clients
      can use to obtain filehandles for these exports via a multi-component
      LOOKUP.  A common user experience is to use a graphical user interface
      (perhaps a file "Open" dialog window) to find a file via progressive
      browsing through a directory tree.  The client must be able to move
      from one export to another export via single-component, progressive
      LOOKUP operations.
    </t>

    <t>
      This style of browsing is not well supported by the NFSv2 and
      NFSv3 protocols.  The client expects all LOOKUP operations to remain
      within a single-server file system.  For example, the device attribute
      will not change.  This prevents a client from taking namespace
      paths that span exports.
    </t>

    <t>
      An automounter on the client can obtain a snapshot of the server's
      namespace using the EXPORTS procedure of the MOUNT protocol.  If it
      understands the server's pathname syntax, it can create an image of
      the server's namespace on the client.  The parts of the namespace
      that are not exported by the server are filled in with a
      "pseudo-file system" that allows the user to browse from one mounted
      file system to another.  There is a drawback to this representation of
      the server's namespace on the client: it is static.  If the server
      administrator adds a new export, the client will be unaware of it.
    </t>

  </section>
  <section title="Server Pseudo-File System">

    <t>
      NFSv4 servers avoid this namespace inconsistency by
      presenting all the exports within the framework of a single-server
      namespace.  An NFSv4 client uses LOOKUP and READDIR
      operations to browse seamlessly from one export to another.  Portions
      of the server namespace that are not exported are bridged via a
      "pseudo-file system" that provides a view of exported directories only.
      A pseudo-file system has a unique fsid and behaves like a normal,
      read-only file system.
    </t>

    <t>
      Based on the construction of the server's namespace, it is possible
      that multiple pseudo-file systems may exist.  For example:

      <figure>
        <artwork>
  /a         pseudo-file system
  /a/b       real file system
  /a/b/c     pseudo-file system
  /a/b/c/d   real file system
        </artwork>
      </figure>
    </t>

    <t>
      Each of the pseudo-file systems are considered separate entities and
      therefore will have a unique fsid.
    </t>

  </section>
  <section title="Multiple Roots">

    <t>
      The DOS and Windows operating environments are sometimes described
      as having "multiple roots".  File systems are commonly represented
      as disk letters.  MacOS represents file systems as top-level names.
      NFSv4 servers for these platforms can construct a
      pseudo-file system above these root names so that disk letters or
      volume names are simply directory names in the pseudo-root.
    </t>

  </section>
  <section title="Filehandle Volatility">

    <t>
      The nature of the server's pseudo-file system is that it is a logical
      representation of file system(s) available from the server.  Therefore,
      the pseudo-file system is most likely constructed dynamically when
      the server is first instantiated.  It is expected that the
      pseudo-file system may not have an on-disk counterpart from which
      persistent filehandles could be constructed.  Even though it is
      preferable that the server provide persistent filehandles for the
      pseudo-file system, the NFS client should expect that
      pseudo-file system filehandles are volatile.  This can be
      confirmed by checking the associated "fh_expire_type" attribute
      for those filehandles in question. If the filehandles are
      volatile, the NFS client must be prepared to recover a
      filehandle value (e.g., with a multi-component LOOKUP) when
      receiving an error of NFS4ERR_FHEXPIRED.
    </t>

  </section>
  <section title="Exported Root">

    <t>
      If the server's root file system is exported, one might conclude that
      a pseudo-file system is not needed.  This would be wrong.  Assume the
      following file systems on a server:

      <figure>
        <artwork>
  /       disk1  (exported)
  /a      disk2  (not exported)
  /a/b    disk3  (exported)
        </artwork>
      </figure>
    </t>

    <t>
      Because disk2 is not exported, disk3 cannot be reached with simple
      LOOKUPs.  The server must bridge the gap with a pseudo-file system.
    </t>

  </section>
  <section title="Mount Point Crossing">

    <t>
      The server file system environment may be constructed in such a
      way that one file system contains a directory that is 'covered'
      or mounted upon by a second file system.  For example:

      <figure>
        <artwork>
  /a/b            (file system 1)
  /a/b/c/d        (file system 2)
        </artwork>
      </figure>
    </t>

    <t>
      The pseudo-file system for this server may be constructed to look like:

      <figure>
        <artwork>
  /               (placeholder/not exported)
  /a/b            (file system 1)
  /a/b/c/d        (file system 2)
        </artwork>
      </figure>
    </t>

    <t>
      It is the server's responsibility to present the pseudo-file system
      that is complete to the client.  If the client sends a LOOKUP request
      for the path "/a/b/c/d", the server's response is the filehandle of
      the file system "/a/b/c/d".  In previous versions of the NFS protocol,
      the server would respond with the filehandle of directory "/a/b/c/d"
      within the file system "/a/b".
    </t>

    <t>
      The NFS client will be able to determine if it crosses a server
      mount point by a change in the value of the "fsid" attribute.
    </t>

  </section>
  <section title="Security Policy and Namespace Presentation">

    <t>
      Because NFSv4 clients possess the ability to change the security
      mechanisms used, after determining what is allowed, by using SECINFO
      the server SHOULD NOT present a different view of
      the namespace based on the security mechanism being used by a client.
      Instead, it should present a consistent view and return
      NFS4ERR_WRONGSEC if an attempt is made to access data with an
      inappropriate security mechanism.
    </t>

    <t>
      If security considerations make it necessary to hide the existence of
      a particular file system, as opposed to all of the data within it,
      the server can apply the security policy of a shared resource in the
      server's namespace to components of the resource's ancestors.  For
      example:
    </t>

    <figure>
      <artwork>
    /                       (placeholder/not exported)
    /a/b                    (file system 1)
    /a/b/MySecretProject    (file system 2)
      </artwork>
    </figure>

    <t>
      The /a/b/MySecretProject directory is a real file system and is the
      shared resource.  Suppose the security policy for /a/b/
      MySecretProject is Kerberos with integrity and it is desired to limit
      knowledge of the existence of this file system.  In this case, the
      server should apply the same security policy to /a/b.  This allows
      for knowledge of the existence of a file system to be secured when
      desirable.
    </t>

    <t>
      For the case of the use of multiple, disjoint security mechanisms in
      the server's resources, applying that sort of policy would result in
      the higher-level file system not being accessible using any security
      flavor.  Therefore, that sort of configuration is not compatible with
      hiding the existence (as opposed to the contents) from clients using
      multiple disjoint sets of security flavors.
    </t>

    <t>
      In other circumstances, a desirable policy is for the security of a
      particular object in the server's namespace to include the union of
      all security mechanisms of all direct descendants.  A common and
      convenient practice, unless strong security requirements dictate
      otherwise, is to make the entire pseudo-file system accessible by
      all of the valid security mechanisms.
    </t>

    <t>
      Where there is concern about the security of data on the network,
      clients should use strong security mechanisms to access the
      pseudo-file system in order to prevent man-in-the-middle attacks.
    </t>
  </section>
</section>

<section anchor="sec:mars" title="Multi-Server Namespace">
  <t>
    NFSv4 supports attributes that allow a namespace to extend
    beyond the boundaries of a single server.  It is RECOMMENDED
    that clients and servers support construction of such
    multi-server namespaces.  Use of such multi-server namespaces
    is optional, however, and for many purposes,
    single-server namespaces are perfectly acceptable.  Use of
    multi-server namespaces can provide many advantages, however, by
    separating a file system's logical position in a namespace from
    the (possibly changing) logistical and administrative
    considerations that result in particular file systems being
    located on particular servers.
  </t>
  <section anchor="location_attrs" title="Location Attributes">
    <t>
      NFSv4 contains RECOMMENDED attributes that allow file systems on
      one server to be associated with one or more instances of that
      file system on other servers.  These attributes specify such
      file system instances by specifying a server address
      target (as either a DNS name representing one or more IP
      addresses, or a literal IP address), together with the path
      of that file system within the associated single-server namespace.
    </t>
    <t>
      The fs_locations RECOMMENDED attribute allows specification of the
      file system locations where the data corresponding to a given file
      system may be found.
    </t>
  </section>
  <section anchor="presence_or_absence" title="File System Presence or Absence">
    <t>
      A given location in an NFSv4 namespace (typically but not necessarily
      a multi-server namespace) can have a number of file system instance
      locations associated with it via the fs_locations
      attribute.  There may also be an actual current file system at
      that location, accessible via normal namespace operations (e.g.,
      LOOKUP).  In this case, the file system is said to be
      "present" at that position in the namespace, and clients will
      typically use it, reserving use of additional locations
      specified via the location-related attributes to situations in
      which the principal location is no longer available.
    </t>
    <t>
      When there is no actual file system at the namespace location
      in question, the file system is said to be "absent".  An absent
      file system contains no files or directories other than the
      root.  Any reference to it, except
      to access a small set of attributes useful in determining
      alternative locations, will result in an error, NFS4ERR_MOVED.
      Note that if the server ever returns the error NFS4ERR_MOVED,
      it MUST support the fs_locations attribute.
    </t>
    <t>
      While the error name suggests that we have a case of a file system
      that once was present, and has only become absent later, this is
      only one possibility.  A position in the namespace may be permanently
      absent with the set of file system(s) designated by the location
      attributes being the only realization.
      The name NFS4ERR_MOVED reflects an earlier,
      more limited conception of its function, but this error will be
      returned whenever the referenced file system is absent, whether it
      has moved or simply never existed.
    </t>
    <t>
      Except in the case of GETATTR-type operations (to be discussed
      later), when the
      current filehandle at the start of an operation is within an
      absent file system, that operation is not performed and the error
      NFS4ERR_MOVED is returned, to indicate that the file system is
      absent on the current server.
    </t>
    <t>
      Because a GETFH cannot succeed if the current filehandle is
      within an absent file system, filehandles within an absent
      file system cannot be transferred to the client.  When a
      client does have filehandles within an absent file system, it
      is the result of obtaining them when the file system was
      present, and having the file system become
      absent subsequently.
    </t>
    <t>
      It should be noted that because the check for the current
      filehandle being within an absent file system happens at the
      start of every operation, operations that change the current
      filehandle so that it is within an absent file system will not
      result in an error.  This allows such combinations as
      PUTFH-GETATTR and LOOKUP-GETATTR to be used to get attribute
      information, particularly location attribute information,
      as discussed below.
    </t>
  </section>
  <section anchor="absent_fs_attributes"
           title="Getting Attributes for an Absent File System">
    <t>
      When a file system is absent, most attributes are not available,
      but it is necessary to allow the client access to the small
      set of attributes that are available, and most particularly
      that which gives information about the correct current locations
      for this file system, fs_locations.
    </t>
    <section anchor="absent_getattr"
             title="GETATTR within an Absent File System">
      <t>
        As mentioned above, an exception is made for GETATTR in that
        attributes may be obtained for a filehandle within an absent
        file system.  This exception only applies if the attribute
        mask contains at least the fs_locations attribute bit, which
        indicates that the client is interested in a result regarding
        an absent file system.  If it is not requested, GETATTR will
        result in an NFS4ERR_MOVED error.
      </t>
      <t>
        When a GETATTR is done on an absent file system, the set of
        supported attributes is very limited.  Many attributes, including
        those that are normally REQUIRED, will not be available on an
        absent file system.  In addition to the fs_locations attribute,
        the following attributes SHOULD be available on absent file
        systems.  In the case of RECOMMENDED attributes, they should
        be available at least to the same degree that they are available
        on present file systems.
      </t>
      <t>
       <list style='hanging'>
        <t hangText="fsid:">
          This attribute should be provided so that the client
          can determine file system boundaries, including, in
          particular, the boundary between present and absent file
          systems.  This value must be different from any other fsid
          on the current server and need have no particular relationship
          to fsids on any particular destination to which the client
          might be directed.
        </t>
        <t hangText="mounted_on_fileid:">
          For objects at the top of an absent
          file system, this attribute needs to be available.  Since
          the fileid is within the present parent file
          system, there should be no need to reference the absent file
          system to provide this information.
        </t>
       </list>
      </t>
      <t>
        Other attributes SHOULD NOT be made available for absent file
        systems, even when it is possible to provide them.  The server
        should not assume that more information is always better and
        should avoid gratuitously providing additional information.
      </t>
      <t>
        When a GETATTR operation includes a bitmask for the
        attribute fs_locations, but
        where the bitmask includes attributes that are not supported,
        GETATTR will not return an error but will return the mask
        of the actual attributes supported with the results.
      </t>
      <t>
        Handling of VERIFY/NVERIFY is similar to GETATTR in that if
        the attribute mask does not include fs_locations
        the error NFS4ERR_MOVED will result.  It differs in
        that any appearance in the attribute mask of an attribute not
        supported for an absent file system (and note that this will
        include some normally REQUIRED attributes) will also cause
        an NFS4ERR_MOVED result.
      </t>
    </section>
    <section anchor="absent_readdir"
             title="READDIR and Absent File Systems">
      <t>
        A READDIR performed when the current filehandle is within an
        absent file system will result in an NFS4ERR_MOVED error,
        since, unlike the case of GETATTR, no such exception is
        made for READDIR.
      </t>
      <t>
        Attributes for an absent file system may be fetched via a
        READDIR for a directory in a present file system, when that
        directory contains the root directories of one or more absent
        file systems.  In this case, the handling is as follows:
      </t>
      <t>
       <list style='symbols'>
        <t>
          If the attribute set requested includes fs_locations, then
          the fetching of attributes proceeds normally, and no
          NFS4ERR_MOVED indication is returned even when the
          rdattr_error attribute is requested.
        </t>
        <t>
          If the attribute set requested does not include
          fs_locations, then if the
          rdattr_error attribute is requested, each directory entry for
          the root of an absent file system will report
          NFS4ERR_MOVED as the value of the rdattr_error attribute.
        </t>
        <t>
          If the attribute set requested does not include either of the
          attributes fs_locations or rdattr_error, then the occurrence
          of the root of an absent file system within the directory
          will result in the READDIR failing with an NFS4ERR_MOVED error.
        </t>
        <t>
          The unavailability of an attribute because of a file system's
          absence, even one that is ordinarily REQUIRED, does not result
          in any error indication.  The set of attributes returned for
          the root directory of the absent file system in that case is
          simply restricted to those actually available.
        </t>
       </list>
      </t>
    </section>
  </section>
  <section anchor="location_uses" title="Uses of Location Information">
    <t>
      The location-bearing attribute of fs_locations
      provides, together with the possibility of absent file systems,
      a number of important facilities in providing reliable, manageable,
      and scalable data access.
    </t>
    <t>
      When a file system is present, these attributes can provide
      alternative locations, to be used to access the same data,
      in the event of server failures, communications problems,
      or other difficulties that make continued access to the current
      file system impossible or otherwise impractical.
      Under some circumstances, multiple alternative locations
      may be used simultaneously to provide higher-performance
      access to the file system in question.  Provision of
      such alternative locations is referred to as "replication",
      although there are cases in which replicated sets of data are
      not in fact present and the replicas are instead different
      paths to the same data.
    </t>
    <t>
      When a file system is present and subsequently becomes absent,
      clients can be given the opportunity to have continued access
      to their data, at an alternative location. Transfer of the
      file system contents to the new location is referred to as
      "migration".  See <xref target='migration' /> for details.
    </t>
    <t>
      Alternative  locations may be physical replicas of the
      file system data or alternative communication paths to the
      same server or, in the case of various forms of server clustering,
      another server providing access to the same physical file
      system.  The client's responsibilities in dealing with this
      transition depend on the specific nature of the new access
      path as well as how and whether data was in fact migrated.
      These issues will be discussed in detail below.
    </t>
    <t>
      Where a file system was not previously present, specification
      of file system location provides a means by which file systems
      located on one server can be associated with a namespace
      defined by another server, thus allowing a general multi-server
      namespace facility.  A designation of such a location, in place
      of an absent file system, is called a "referral".
    </t>
    <t>
      Because client support for location-related attributes is
      OPTIONAL, a server may (but is not required to) take action
      to hide migration and referral events from such clients, by
      acting as a proxy, for example.
    </t>
    <section anchor="replication" title="File System Replication">
      <t>
        The fs_locations attribute provides alternative locations,
        to be used to access data in place of, or in addition to,
        the current file system instance.  On first access to a
        file system, the client should obtain the value of the set
        of alternative locations by interrogating the fs_locations
        attribute.
      </t>
      <t>
        In the event that server failures, communications problems,
        or other difficulties make continued access to the current
        file system impossible or otherwise impractical, the client
        can use the alternative locations as a way to get continued
        access to its data.  Multiple locations may
        be used simultaneously, to provide higher performance
        through the exploitation of multiple paths between client
        and target file system.
      </t>
      <t>
        Multiple server addresses, whether they are derived from
        a single entry with a DNS name representing a set of IP
        addresses or from multiple entries each with its own
        server address, may correspond to the same actual
        server.
      </t>
    </section>
    <section anchor="migration" title="File System Migration">
      <t>
        When a file system is present and becomes absent, clients can be
        given the opportunity to have continued access to their data,
        at an alternative location, as specified by the fs_locations
        attribute.  Typically, a client will be
        accessing the file system in question, get an NFS4ERR_MOVED
        error, and then use the fs_locations
        attribute to determine the new location of the data.
      </t>
      <t>
        Such migration can be helpful in providing
        load balancing or general resource reallocation.  The protocol
        does not specify how the file system will be moved between
        servers.  It is anticipated that a number of different
        server-to-server transfer mechanisms might be used, with the
        choice left to the server implementer.  The NFSv4 protocol
        specifies the method used to communicate the migration
        event between client and server.
      </t>
      <t>
        When an alternative location is designated as the target for
        migration, it must designate the same data.
        Where file systems are writable,
        a change made on the original file system must be visible on
        all migration targets. Where a file system is not writable
        but represents a read-only copy (possibly periodically
        updated) of
        a writable file system, similar requirements apply to the
        propagation of updates.  Any change visible in the original
        file system must already be effected on all migration targets,
        to avoid any
        possibility that a client, in effecting a transition to
        the migration target, will see any reversion in file system state.
      </t>
    </section>
    <section anchor="referrals" title="Referrals">
      <t>
        Referrals provide a way of placing a file system in a location
        within the namespace
        essentially without respect to its physical location on a
        given server.  This allows a single server or a set of servers
        to present a multi-server namespace that encompasses file systems
        located on multiple servers.  Some likely uses of this include
        establishment of site-wide or organization-wide namespaces,
        or even knitting such together into a truly global namespace.
      </t>
      <t>
        Referrals occur when a client determines, upon first referencing
        a position in the current namespace, that it is part of a new
        file system and that the file system is absent.  When this
        occurs, typically by receiving the error NFS4ERR_MOVED, the
        actual location or locations of the file system can be
        determined by fetching the fs_locations attribute.
      </t>
      <t>
        The location-related attribute may designate a single
        file system location or multiple file system locations, to
        be selected based on the needs of the client.
      </t>
      <t>
        Use of multi-server namespaces is enabled by NFSv4 but is not
        required.  The use of multi-server namespaces and their scope
        will depend on the applications used and system administration
        preferences.
      </t>
      <t>
        Multi-server namespaces can be established by a single
        server providing a large set of referrals to all of the
        included file systems.  Alternatively, a single multi-server
        namespace may be administratively segmented with separate
        referral file systems (on separate servers) for each
        separately administered portion of the namespace.  The
        top-level referral file system or any segment  may use
        replicated referral file systems for higher availability.
      </t>
      <t>
        Generally, multi-server namespaces are for the most part
        uniform, in that the same data made available to one client
        at a given location in the namespace is made available to
        all clients at that location.
      </t>
    </section>
  </section>
  <section title="Location Entries and Server Identity"
           anchor="loc_server_id">
    <t>
      As mentioned above, a single location entry may have a server
      address target in the form of a DNS name that may represent
      multiple
      IP addresses, while multiple location entries may have their
      own server address targets that reference the same server.
    </t>
    <t>
      When multiple addresses for the same server exist, the client
      may assume that for each file system in the namespace of
      a given server network address, there exist
      file systems at corresponding namespace locations for
      each of the other server network addresses.
      It may do this even in the absence of
      explicit listing in fs_locations.
      Such corresponding file system locations can be used as
      alternative locations, just as those explicitly specified via
      the fs_locations attribute.
    </t>
    <t>
      If a single location entry designates multiple server IP addresses,
      the client should choose a single one to use.
      When two server addresses are designated
      by a single location entry and they correspond to different
      servers, this normally indicates some sort of misconfiguration,
      and so the client should avoid using such location entries
      when alternatives are available.  When they are not,
      clients should pick one of the IP addresses and use it,
      without using others that are not directed to the same
      server.
    </t>
  </section>
  <section title="Additional Client-Side Considerations">
    <t>
      When clients make use of servers that implement referrals,
      replication, and
      migration, care should be taken that a user who mounts a given
      file system that includes a referral or a relocated file system
      continues to see a coherent picture of that user-side file system
      despite the fact that it contains a number of server-side
      file systems that may be on different servers.
    </t>
    <t>
      One important issue is upward navigation from the root of a
      server-side file system to its parent (specified as ".." in UNIX),
      in the case in which it transitions to that file system as a
      result of referral, migration, or a transition as a result of
      replication.  When the client is at such a point, and it needs to ascend to
      the parent, it must go back to the parent as seen within the
      multi-server namespace rather than sending a LOOKUPP operation to the
      server, which would result in the parent within that server's
      single-server namespace.  In order to do this, the client
      needs to remember the filehandles that represent such
      file system roots and use these instead of issuing a
      LOOKUPP operation to the current server.  This will allow the client
      to present to applications a consistent namespace, where
      upward navigation and downward navigation are consistent.
    </t>
    <t>
      Another issue concerns refresh of referral locations.  When
      referrals are used extensively, they may change as server
      configurations change.  It is expected that clients will cache
      information related to traversing referrals so that future client-side
      requests are resolved locally without server communication.
      This is usually rooted in client-side name lookup caching. Clients
      should periodically purge this data for referral points in order to
      detect changes in location information.
    </t>
    <t>
      A potential problem exists if a client were to allow an open-owner to
      have state on multiple file systems on a server, in that it is unclear
      how the sequence numbers associated with open-owners are to be dealt
      with, in the event of transparent state migration.  A client can avoid
      such a situation if it ensures that any use of an open-owner is
      confined to a single file system.
    </t>

    <t>
      A server MAY decline to migrate state associated with open-owners that
      span multiple file systems.  In cases in which the server chooses not
      to migrate such state, the server MUST return NFS4ERR_BAD_STATEID
      when the client uses those stateids on the new server.
    </t>

    <t>
      The server MUST return NFS4ERR_STALE_STATEID  when the client
      uses those stateids on the old server, regardless of whether
      migration has occurred or not.
    </t>
  </section>

  <section anchor="effecting_referrals"
           title="Effecting File System Referrals">
    <t>
      Referrals are effected when an absent file system is encountered
      and one or more alternative locations are made available by the
      fs_locations attribute.  The client will
      typically get an NFS4ERR_MOVED error, fetch the appropriate
      location information, and proceed to access the file system on
      a different server, even though it retains its logical position
      within the original namespace.  Referrals differ from migration
      events in that they happen only when the client has not
      previously referenced the file system in question (so there
      is nothing to transition).  Referrals can only come into
      effect when an absent file system is encountered at its root.
    </t>
    <t>
      The examples given in the sections below are somewhat artificial in
      that an actual client will not typically do a multi-component
      lookup but will have cached information regarding the upper levels
      of the name hierarchy.  However, these example are chosen to make
      the required behavior clear and easy to put within the scope of a
      small number of requests, without getting unduly into details of
      how specific clients might choose to cache things.
    </t>
    <section anchor="referrals_lookup"
             title="Referral Example (LOOKUP)">
      <t>
        Let us suppose that the following COMPOUND is sent in an
        environment in which /this/is/the/path is absent from the
        target server.  This may be for a number of reasons.  It may
        be the case that the
        file system has moved, or it may be the case that
        the target server is functioning mainly, or solely, to refer
        clients to the servers on which various file systems are located.
      </t>
      <t>
       <list style='symbols'>
        <t>
          PUTROOTFH
        </t>
        <t>
          LOOKUP "this"
        </t>
        <t>
          LOOKUP "is"
        </t>
        <t>
          LOOKUP "the"
        </t>
        <t>
          LOOKUP "path"
        </t>
        <t>
          GETFH
        </t>
        <t>
          GETATTR(fsid, fileid, size, time_modify)
        </t>
       </list>
      </t>
      <t>
        Under the given circumstances, the following will be the result:
      </t>
      <t>
       <list style='symbols'>
        <t>
          PUTROOTFH  --> NFS_OK.  The current fh is now the root of
          the pseudo-fs.
        </t>
        <t>
          LOOKUP "this" --> NFS_OK.  The current fh is for /this and is
          within the pseudo-fs.
        </t>
        <t>
          LOOKUP "is" --> NFS_OK.  The current fh is for /this/is
          and is within the pseudo-fs.
        </t>
        <t>
          LOOKUP "the" --> NFS_OK.  The current fh is for /this/is/the
          and is within the pseudo-fs.
        </t>
        <t>
          LOOKUP "path" --> NFS_OK.  The current fh is for
          /this/is/the/path and is within a new, absent file system,
          but ...&nbsp;the client will never see the value of that fh.
        </t>
        <t>
          GETFH --> NFS4ERR_MOVED.
          Fails, because the current fh is in an absent file system at
          the start of the operation and the specification makes
          no exception for GETFH.
        </t>
        <t>
          GETATTR(fsid, fileid, size, time_modify).
          Not executed, because the failure of the GETFH stops the
          processing of the COMPOUND.
        </t>
       </list>
      </t>
      <t>
        Given the failure of the GETFH, the client has the job of
        determining the root of the absent file system and where to find
        that file system, i.e., the server and path relative to that
        server's root fh.  Note here that in this example, the client did
        not obtain filehandles and attribute information (e.g., fsid) for
        the intermediate directories, so that it would not be sure where
        the absent file system starts.  It could be the case, for example,
        that /this/is/the is the root of the moved file system and that
        the reason that the lookup of "path" succeeded is that the
        file system was not absent on that operation but was moved
        between the last LOOKUP and the GETFH (since COMPOUND is not
        atomic).  Even if we had the fsids for all of the intermediate
        directories, we could have no way of knowing that /this/is/the/path
        was the root of a new file system, since we don't yet have its fsid.
      </t>
      <t>
        In order to get the necessary information, let us re-send the
        chain of LOOKUPs with GETFHs and GETATTRs to at least get the
        fsids so we can be sure where the appropriate file system
        boundaries are. The client could choose to get fs_locations at
        the same time, but in most cases the client will have a good
        guess as to where the file system boundaries are (because of
        where NFS4ERR_MOVED was, and was not, received), making the
        fetching of fs_locations unnecessary.
      </t>
      <t>
       <list style='hanging'>
        <t hangText='OP01:'>
          PUTROOTFH  --> NFS_OK
        </t>
        <t hangText='- '>
          The current fh is at the root of the pseudo-fs.
        </t>
        <t hangText='OP02:'>
          GETATTR(fsid)  --> NFS_OK
        </t>
        <t hangText='- '>
          Just for completeness.  Normally, clients will know the fsid
          of the pseudo-fs as soon as they establish communication with
          a server.
        </t>
        <t hangText='OP03:'>
          LOOKUP "this" --> NFS_OK
        </t>
        <t hangText='OP04:'>
          GETATTR(fsid)  --> NFS_OK
        </t>
        <t hangText='- '>
          Get the current fsid to see where the file system
          boundaries are.  The fsid will be that for the
          pseudo-fs in this example, so no boundary.
        </t>
        <t hangText='OP05:'>
          GETFH --> NFS_OK
        </t>
        <t hangText='- '>
          The current fh is for /this and is within the pseudo-fs.
        </t>
        <t hangText='OP06:'>
          LOOKUP "is" --> NFS_OK
        </t>
        <t hangText='- '>
          The current fh is for /this/is and is within the pseudo-fs.
        </t>
        <t hangText='OP07:'>
          GETATTR(fsid)  --> NFS_OK
        </t>
        <t hangText='- '>
          Get the current fsid to see where the file system
          boundaries are.  The fsid will be that for the pseudo-fs
          in this example, so no boundary.
        </t>
        <t hangText='OP08:'>
          GETFH --> NFS_OK
        </t>
        <t hangText='- '>
          The current fh is for /this/is and is within the pseudo-fs.
        </t>
        <t hangText='OP09:'>
          LOOKUP "the" --> NFS_OK
        </t>
        <t hangText='- '>
          The current fh is for /this/is/the and is within the pseudo-fs.
        </t>
        <t hangText='OP10:'>
          GETATTR(fsid)  --> NFS_OK
        </t>
        <t hangText='- '>
          Get the current fsid to see where the file system boundaries are.
          The fsid will be that for the pseudo-fs in this example, so no
          boundary.
        </t>
        <t hangText='OP11:'>
          GETFH --> NFS_OK
        </t>
        <t hangText='- '>
          The current fh is for /this/is/the and is within the pseudo-fs.
        </t>
        <t hangText='OP12:'>
          LOOKUP "path" --> NFS_OK
        </t>
        <t hangText='- '>
          The current fh is for /this/is/the/path and is within a new,
          absent file system, but ...
        </t>
        <t hangText='- '>
          The client will never see the value of that fh.
        </t>
        <t hangText='OP13:'>
          GETATTR(fsid, fs_locations)  --> NFS_OK
        </t>
        <t hangText='- '>
          We are getting the fsid to know where the file system boundaries are.
          In this operation, the fsid will be different than that of the
          parent directory (which in turn was retrieved in OP10).
          Note that the
          fsid we are given will not necessarily be preserved at the new
          location.  That fsid might be different, and in fact the fsid
          we have for this file system might be a valid fsid of a different
          file system on that new server.
        </t>
        <t hangText='- '>
          In this particular case, we are pretty sure anyway that what
          has moved is /this/is/the/path rather than /this/is/the
          since we have the fsid of the latter and it is that of the
          pseudo-fs, which presumably cannot move.  However, in other
          examples, we might not have this kind of information to rely
          on (e.g., /this/is/the might be a non-pseudo-file system
          separate from /this/is/the/path), so we need to have
          other reliable source information on the boundary of the file system
          that is moved.  If, for example, the file system /this/is
          had moved, we would have a case of migration rather than
          referral, and once the boundaries of the migrated file system
          were clear we could fetch fs_locations.
        </t>
        <t hangText='- '>
          We are fetching fs_locations because the fact that we got an
          NFS4ERR_MOVED at this point means that this is most likely a
          referral and we need the destination.  Even if it is the
          case that /this/is/the is a file system that has migrated,
          we will still need the location information for that file system.
        </t>
        <t hangText='OP14:'>
          GETFH --> NFS4ERR_MOVED
        </t>
        <t hangText='- '>
          Fails because current fh is in an absent file system at the start of
          the operation, and the specification makes no exception for GETFH.  Note
          that this means the server will never send the client a
          filehandle from within an absent file system.
        </t>
       </list>
      </t>
      <t>
        Given the above, the client knows where the root of the absent file
        system is (/this/is/the/path) by noting where the change of fsid
        occurred (between "the" and "path").  The fs_locations attribute
        also gives the client the actual location of the absent
        file system so that the referral can proceed.  The
        server gives the client the bare minimum of information about the
        absent file system so that there will be very little scope for
        problems of conflict between information sent by the referring
        server and information of the file system's home.  No filehandles
        and very few attributes are present on the referring server, and the
        client can treat those it receives as transient
        information with the function of enabling the referral.
      </t>
    </section>
    <section anchor="referrals_readdir"
             title="Referral Example (READDIR)">
      <t>
        Another context in which a client may encounter referrals is when
        it does a READDIR on a directory in which some of the subdirectories
        are the roots of absent file systems.
      </t>
      <t>
        Suppose such a directory is read as follows:
      </t>
      <t>
       <list style='symbols'>
        <t>
          PUTROOTFH
        </t>
        <t>
          LOOKUP "this"
        </t>
        <t>
          LOOKUP "is"
        </t>
        <t>
          LOOKUP "the"
        </t>
        <t>
          READDIR(fsid, size, time_modify, mounted_on_fileid)
        </t>
       </list>
      </t>
      <t>
        In this case, because rdattr_error is not requested, fs_locations
        is not requested, and some of the attributes cannot be provided, the
        result will be an NFS4ERR_MOVED error on the READDIR, with the
        detailed results as follows:
      </t>
      <t>
       <list style='symbols'>
        <t>
          PUTROOTFH  --> NFS_OK.  The current fh is at the root of the
          pseudo-fs.
        </t>
        <t>
          LOOKUP "this" --> NFS_OK. The current fh is for /this and is
          within the pseudo-fs.
        </t>
        <t>
          LOOKUP "is" --> NFS_OK.  The current fh is for /this/is
          and is within the pseudo-fs.
        </t>
        <t>
          LOOKUP "the" --> NFS_OK.  The current fh is for /this/is/the
          and is within the pseudo-fs.
        </t>
        <t>
          READDIR(fsid, size, time_modify, mounted_on_fileid) -->
          NFS4ERR_MOVED.  Note that the same error would have been
          returned if /this/is/the had migrated, but it is returned because the
          directory contains the root of an absent file system.
        </t>
       </list>
      </t>
      <t>
        So now suppose that we re-send with rdattr_error:
      </t>
      <t>
       <list style='symbols'>
        <t>
          PUTROOTFH
        </t>
        <t>
          LOOKUP "this"
        </t>
        <t>
          LOOKUP "is"
        </t>
        <t>
          LOOKUP "the"
        </t>
        <t>
          READDIR(rdattr_error, fsid, size, time_modify, mounted_on_fileid)
        </t>
       </list>
      </t>
      <t>
        The results will be:
      </t>
      <t>
       <list style='symbols'>
        <t>
          PUTROOTFH  --> NFS_OK.  The current fh is at the root of the
          pseudo-fs.
        </t>
        <t>
          LOOKUP "this" --> NFS_OK. The current fh is for /this and is
          within the pseudo-fs.
        </t>
        <t>
          LOOKUP "is" --> NFS_OK.  The current fh is for /this/is
          and is within the pseudo-fs.
        </t>
        <t>
          LOOKUP "the" --> NFS_OK.  The current fh is for /this/is/the
          and is within the pseudo-fs.
        </t>
        <t>
          READDIR(rdattr_error, fsid, size, time_modify, mounted_on_fileid)
          --> NFS_OK.  The attributes for the directory entry with the
          component named "path" will only contain rdattr_error
          with the value NFS4ERR_MOVED, together with an fsid
          value and a value for mounted_on_fileid.
        </t>
       </list>
      </t>
      <t>
        So suppose we do another READDIR to get fs_locations (although
        we could have used a GETATTR directly, as in
        <xref target="referrals_lookup" />):
      </t>
      <t>
       <list style='symbols'>
        <t>
          PUTROOTFH
        </t>
        <t>
          LOOKUP "this"
        </t>
        <t>
          LOOKUP "is"
        </t>
        <t>
          LOOKUP "the"
        </t>
        <t>
          READDIR(rdattr_error, fs_locations, mounted_on_fileid, fsid,
          size, time_modify)
        </t>
       </list>
      </t>
      <t>
        The results would be:
      </t>
      <t>
       <list style='symbols'>
        <t>
          PUTROOTFH  --> NFS_OK.  The current fh is at the root of the
          pseudo-fs.
        </t>
        <t>
          LOOKUP "this" --> NFS_OK. The current fh is for /this and is
          within the pseudo-fs.
        </t>
        <t>
          LOOKUP "is" --> NFS_OK.  The current fh is for /this/is
          and is within the pseudo-fs.
        </t>
        <t>
          LOOKUP "the" --> NFS_OK.  The current fh is for /this/is/the
          and is within the pseudo-fs.
        </t>
        <t>
          READDIR(rdattr_error, fs_locations, mounted_on_fileid, fsid,
          size, time_modify) --> NFS_OK.  The attributes will be as
          shown below.
        </t>
       </list>
      </t>
      <t>
         The attributes for the directory entry with the
         component named "path" will only contain:
      </t>
      <t>
       <list style='symbols'>
        <t>
          rdattr_error (value: NFS_OK)
        </t>
        <t>
          fs_locations
        </t>
        <t>
          mounted_on_fileid (value: unique fileid within referring file system)
        </t>
        <t>
          fsid (value: unique value within referring server)
        </t>
       </list>
      </t>
      <t>
        The attributes for entry "path" will not contain size or
        time_modify, because these attributes are not available within an
        absent file system.
      </t>
    </section>
  </section>

  <section anchor="fs_locations" title="The Attribute fs_locations">
    <t>
      The fs_locations attribute is defined by both fs_location4
      (<xref target='fs_location4' />) and fs_locations4
      (<xref target='fs_locations4' />).
      It is used to represent the location of a
      file system by providing a server name and the path to the root
      of the file system within that server's namespace.
      When a set of servers have corresponding file systems at the
      same path within their namespaces, an array of server names may
      be provided.  An entry in the server array is a UTF-8 string
      and represents one of a traditional DNS host name, IPv4 address,
      IPv6 address, or a zero-length string.
      A zero-length string SHOULD be used to indicate the current address
      being used for the RPC. It is not a requirement that all
      servers that share the same rootpath be listed
      in one fs_location4 instance.  The array of server names is provided for
      convenience.  Servers that share the same rootpath may also be listed
      in separate fs_location4 entries in the fs_locations attribute.
    </t>
    <t>
     The fs_locations4 data type and fs_locations attribute contain an
     array of such locations.  Since the namespace of each server may be
     constructed differently, the fs_root field is provided.  The
     path represented by the fs_root represents the location of the
     file system in the current server's namespace, i.e., that of the
     server from which the fs_locations attribute was obtained.  The
     fs_root path is meant to aid the client by clearly referencing
     the root of the file system whose locations are being reported,
     no matter what object within the current file system the
     current filehandle designates.  The fs_root is simply the
     pathname the client used to reach the object on the current server
     (i.e., the object to which the fs_locations attribute applies).
    </t>
    <t>
     When the fs_locations attribute
     is interrogated and there are no alternative file system locations,
     the server SHOULD return a zero-length array of fs_location4
     structures, together with a valid fs_root.
   </t>
   <t>
     As an example, suppose there is a replicated file system located at two
     servers (servA and servB).  At servA, the file system is located at
     path /a/b/c.  At servB, the file system is located at path /x/y/z.
     If the client were to obtain the fs_locations value for the
     directory at /a/b/c/d, it might not necessarily know
     that the file system's root is located in servA's namespace
     at /a/b/c.  When the client switches to servB, it will need
     to determine that the directory it first referenced at servA is now
     represented by the path /x/y/z/d on servB.  To facilitate this, the
     fs_locations attribute provided by servA would have an fs_root value
     of /a/b/c and two entries in fs_locations.  One entry in fs_locations
     will be for itself (servA), and the other will be for servB with a
     path of /x/y/z.  With this information, the client is able to
     substitute /x/y/z for /a/b/c at the beginning of its access
     path and construct /x/y/z/d to use for the new server.
   </t>
   <t>
     Note that there is no requirement that the number
     of components in each rootpath be the same; there
     is no relation between the number of components in the
     rootpath or fs_root, and none of the components
     in each rootpath and fs_root have to be the same. In
     the above example, we could have had a third element
     in the locations array, with server equal to "servC"
     and rootpath equal to "/I/II", and a fourth element in the
     locations array, with server equal to "servD" and rootpath
     equal to "/aleph/beth/gimel/daleth/he".
   </t>
   <t>
     The relationship between an fs_root and a rootpath is
     that the client replaces the pathname indicated in the
     fs_root for the current server for the substitute
     indicated in the rootpath for the new server.
   </t>
   <t>
     For an example of a referred or migrated file
     system, suppose there is a file system located
     at serv1. At serv1, the file system is located at
     /az/buky/vedi/glagoli. The client finds that the object
     at glagoli has migrated (or is a referral).  The
     client gets the fs_locations attribute, which contains
     an fs_root of /az/buky/vedi/glagoli, and one element
     in the locations array, with server equal to serv2,
     and rootpath equal to /izhitsa/fita. The client
     replaces /az/buky/vedi/glagoli with /izhitsa/fita
     and uses the latter pathname on serv2.
   </t>
   <t>
     Thus, the server MUST return an fs_root that is equal
     to the path the client used to reach the object to which the
     fs_locations attribute applies. Otherwise, the
     client cannot determine the new path to use on the new server.
   </t>
  </section>
</section>

<section anchor="sec:lock_share" title="File Locking and Share Reservations">
  <t>
    Integrating locking into the NFS protocol necessarily causes it
    to be stateful.  With the inclusion of share reservations, the
    protocol becomes substantially more dependent on state than the
    traditional combination of NFS and NLM (Network Lock Manager)
    <xref target="xnfs" />.  There are three
    components to making this state manageable:

    <list style='symbols'>
      <t>
        clear division between client and server
      </t>

      <t>
        ability to reliably detect inconsistency in state between
        client and server
      </t>

      <t>
        simple and robust recovery mechanisms
      </t>
    </list>
  </t>

  <t>
    In this model, the server owns the state information.  The client
    requests changes in locks, and the server responds with the changes
    made.  Non-client-initiated changes in locking state are infrequent.
    The client receives prompt notification of such changes and can
    adjust its view of the locking state to reflect the server's changes.
  </t>

  <t>
    Individual pieces of state created by the server and passed to the
    client at its request are represented by 128-bit stateids.  These
    stateids may represent a particular open file, a set of byte-range
    locks held by a particular owner, or a recallable delegation of
    privileges to access a file in particular ways or at a particular
    location.
  </t>

  <t>
    In all cases, there is a transition from the most general information
    that represents a client as a whole to the eventual lightweight
    stateid used for most client and server locking interactions.  The
    details of this transition will vary with the type of object, but it
    always starts with a client ID.
  </t>

  <t>
    To support Win32 share reservations, it is necessary to atomically
    OPEN or CREATE files and apply the appropriate locks in the same
    operation.  Having a separate share/unshare operation
    would not allow correct implementation of the Win32 OpenFile API.
    In order to correctly implement share semantics, the previous
    NFS protocol mechanisms used when a file is opened or created
    (LOOKUP, CREATE, ACCESS) need to be replaced.  The NFSv4 protocol
    has an OPEN operation that subsumes the NFSv3 methodology of
    LOOKUP, CREATE, and ACCESS.  However, because
    many operations require a filehandle, the traditional LOOKUP is
    preserved to map a filename to a filehandle without establishing
    state on the server.  The policy of granting access or modifying
    files is managed by the server based on the client's state.
    These mechanisms can implement policy ranging from advisory only
    locking to full mandatory locking.
  </t>

  <section title="Opens and Byte-Range Locks" >
    <t>
      It is assumed that manipulating a byte-range lock is rare when
      compared to READ and WRITE operations.  It is also assumed that
      server restarts and network
      partitions are relatively rare.  Therefore, it is important that the
      READ and WRITE operations have a lightweight mechanism to indicate if
      they possess a held lock.  A byte-range lock request contains the
      heavyweight information required to establish a lock and uniquely
      define the owner of the lock.
    </t>

    <t>
      The following sections describe the transition from the
      heavyweight information to the eventual stateid used for most
      client and server locking and lease interactions.
    </t>

    <section anchor="ss:fl:client_id" title="Client ID">

      <t>
        For each LOCK request, the client must identify itself to the
        server.  This is done in such a way as to allow for correct lock
        identification and crash recovery.  A sequence of a SETCLIENTID
        operation followed by a SETCLIENTID_CONFIRM operation is
        required to establish the identification onto the server.
        Establishment of identification by a new incarnation of the
        client also has the effect of immediately breaking any leased
        state that a previous incarnation of the client might have had on
        the server, as opposed to forcing the new client incarnation to
        wait for the leases to expire.  Breaking the lease state amounts
        to the server removing all lock, share reservation, and, where
        the server is not supporting the CLAIM_DELEGATE_PREV claim type,
        all delegation state associated with the same client
        with the same identity.  For a discussion of delegation state
        recovery, see <xref target="ss:cc:deleg_recovery" />.
      </t>

      <t>
        Owners of opens and owners of byte-range locks are separate
        entities and remain separate even if the same opaque arrays
        are used to designate owners of each.  The protocol distinguishes
        between open-owners (represented by open_owner4 structures)
        and lock-owners (represented by lock_owner4 structures).
      </t>
      <t>
        Both sorts of owners consist of a clientid and an opaque
        owner string.  For each client, the set of distinct owner values
        used with that client constitutes the set of owners of that type,
        for the given client.
      </t>

      <t>
        Each open is associated with a specific open-owner, while each
        byte-range lock is associated with a lock-owner and an
        open-owner, the latter being the open-owner associated with the
        open file under which the LOCK operation was done.
      </t>

      <t>
        Client identification is encapsulated in the following structure:

<figure>
 <artwork>
struct nfs_client_id4 {
        verifier4       verifier;
        opaque          id&lt;NFS4_OPAQUE_LIMIT>;
};
 </artwork>
</figure>
      </t>

      <t>
        The first field, verifier, is a client incarnation verifier that is
        used to detect client reboots.  Only if the verifier is different
        from that which the server has previously recorded for the client
        (as identified by the second field of the structure, id) does the
        server start the process of canceling the client's leased state.
      </t>

      <t>
        The second field, id, is a variable-length string that uniquely
        defines the client.
      </t>

      <t>
        There are several considerations for how the client generates
        the id string:

        <list style='symbols'>
          <t>
            The string should be unique so that multiple clients do not
            present the same string.  The consequences of two clients
            presenting the same string range from one client getting
            an error to one client having its leased state abruptly and
            unexpectedly canceled.
          </t>

          <t>
            The string should be selected so the subsequent incarnations
            (e.g., reboots) of the same client cause the client to present
            the same string.  The implementer is cautioned against an
            approach that requires the string to be recorded in a local
            file because this precludes the use of the implementation
            in an environment where there is no local disk and all file
            access is from an NFSv4 server.
          </t>

          <t>
            The string should be different for each server network address
            that the client accesses, rather than common to all server
            network addresses.  The reason is that it may not be possible
            for the client to tell if the same server is listening on
            multiple network addresses.  If the client issues SETCLIENTID
            with the same id string to each network address of such a
            server, the server will think it is the same client, and each
            successive SETCLIENTID will cause the server to begin the
            process of removing the client's previous leased state.
          </t>

          <t>
            The algorithm for generating the string should not assume that
            the client's network address won't change.  This includes
            changes between client incarnations and even changes while
            the client is still running in its current incarnation.
            This means that if the client includes just the client's and
            server's network address in the id string, there is a real risk,
            after the client gives up the network address, that another
            client, using a similar algorithm for generating the id string,
            will generate a conflicting id string.
          </t>
        </list>
      </t>

      <t>
        Given the above considerations, an example of a well-generated
        id string is one that includes:

        <list style='symbols'>
          <t>
            The server's network address.
          </t>

          <t>
            The client's network address.
          </t>

          <t>
            For a user-level NFSv4 client, it should contain
            additional information to distinguish the client from
            other user-level clients running on the same host,
            such as a universally unique identifier (UUID).
          </t>

          <t>
            Additional information that tends to be unique, such as one
            or more of:

            <list style='symbols'>
              <t>
                The client machine's serial number (for privacy reasons,
                it is best to perform some one-way function on the serial
                number).
              </t>

              <t>
                A MAC address (for privacy reasons, it is best to perform
                some one-way function on the MAC address).
              </t>

              <t>
                The timestamp of when the NFSv4 software was
                first installed on the client (though this is subject to
                the previously mentioned caution about using information
                that is stored in a file, because the file might only be
                accessible over NFSv4).
              </t>

              <t>
                A true random number.  However, since this number ought to
                be the same between client incarnations, this shares the
                same problem as that of using the timestamp of the
                software installation.
              </t>
            </list>
          </t>
        </list>
      </t>

      <t>
        As a security measure, the server MUST NOT cancel a client's
        leased state if the principal that established the state for a given
        id string is not the same as the principal issuing the SETCLIENTID.
      </t>

      <t>
        Note that SETCLIENTID (<xref target='OP_SETCLIENTID' />)
        and SETCLIENTID_CONFIRM (<xref target='OP_SETCLIENTID_CONFIRM' />)
        have a secondary purpose of establishing the information the
        server needs to make callbacks to the client for the purpose of
        supporting delegations. It is permitted to change this
        information via SETCLIENTID and SETCLIENTID_CONFIRM within the
        same incarnation of the client without removing the client's
        leased state.
      </t>

      <t>
        Once a SETCLIENTID and SETCLIENTID_CONFIRM sequence has
        successfully completed, the client uses the shorthand client
        identifier, of type clientid4, instead of the longer and less
        compact nfs_client_id4 structure.  This shorthand client identifier
        (a client ID) is assigned by the server and should be chosen so
        that it will not conflict with a client ID previously assigned
        by the server.  This applies across server restarts or reboots.
        When a client ID is presented to a server and that client ID is not
        recognized, as would happen after a server reboot, the server
        will reject the request with the error NFS4ERR_STALE_CLIENTID.
        When this happens, the client must obtain a new client ID by
        use of the SETCLIENTID operation and then proceed to any other
        necessary recovery for the server reboot case (see
        <xref target="ss:fl:sfr" />).
      </t>

      <t>
        The client must also employ the SETCLIENTID operation when it
        receives an NFS4ERR_STALE_STATEID error using a stateid derived
        from its current client ID, since this also indicates a server
        reboot, which has invalidated the existing client ID (see
        <xref target="ss:fl:sfr" /> for details).
      </t>

      <t>
        See the detailed descriptions of SETCLIENTID
        (<xref target='OP_SETCLIENTID_DESCRIPTION' />) and
        SETCLIENTID_CONFIRM (<xref target='OP_SETCLIENTID_CONFIRM_DESCRIPTION' />)
        for a complete specification of the operations.
      </t>

    </section>
    <section title="Server Release of Client ID">

      <t>
        If the server determines that the client holds no associated state
        for its client ID, the server may choose to release the client ID.
        The server may make this choice for an inactive client so that
        resources are not consumed by those intermittently active clients.
        If the client contacts the server after this release, the server
        must ensure that the client receives the appropriate error so that
        it will use the SETCLIENTID/SETCLIENTID_CONFIRM sequence to establish
        a new identity.  It should be clear that the server must be very
        hesitant to release a client ID since the resulting work on the
        client to recover from such an event will be the same burden
        as if the server had failed and restarted.  Typically, a server
        would not release a client ID unless there had been no activity
        from that client for many minutes.
      </t>

      <t>
        Note that if the id string in a SETCLIENTID request is properly
        constructed, and if the client takes care to use the same principal
        for each successive use of SETCLIENTID, then, barring an active
        denial-of-service attack, NFS4ERR_CLID_INUSE should never be
        returned.
      </t>

      <t>
        However, client bugs, server bugs, or perhaps a deliberate change
        of the principal owner of the id string (such as the case of a
        client that changes security flavors, and under the new flavor
        there is no mapping to the previous owner) will in rare cases
        result in NFS4ERR_CLID_INUSE.
      </t>

      <t>
        In that event, when the server gets a SETCLIENTID for a client ID
        that currently has no state, or it has state but the lease has
        expired, rather than returning NFS4ERR_CLID_INUSE, the server MUST
        allow the SETCLIENTID and confirm the new client ID if followed
        by the appropriate SETCLIENTID_CONFIRM.
      </t>
    </section>

    <section anchor="ss:fl:seqids" title="Use of Seqids">
      <t>
        In several contexts, 32-bit sequence values called "seqids" are
        used as part of managing locking state.  Such values are used:
        <list style="symbols">
           <t>
             To provide an ordering of locking-related operations associated
             with a particular lock-owner or open-owner.  See
             <xref target="ss:fl:seqlock"/> for a detailed explanation.
           </t>
           <t>
             To define an ordered set of instances of a set of locks
             sharing a particular set of ownership characteristics.  See
             <xref target="ss:fl:ss"/> for a detailed explanation.
           </t>
        </list>
      </t>
      <t>
        Successive seqid values for the same object are normally arrived
        at by incrementing the current value by one. This pattern continues
        until the seqid is incremented past NFS4_UINT32_MAX, in which case
        one (rather than zero) is to be the next seqid value.
      </t>
      <t>
        When two seqid values are to be compared to determine which of the
        two is later, the possibility of wraparound needs to be considered.
        In many cases, the values are such that simple numeric comparisons
        can be used.  For example, if the seqid values to be compared are
        both less than one million, the higher value can be considered
        the later.  On the other hand, if one of the values is at or near
        NFS_UINT32_MAX and the other is less than one million, then
        implementations can reasonably decide that the lower value has
        had one more wraparound and is thus, while numerically lower,
        actually later.
      </t>
      <t>
        Implementations can compare seqids in the presence of potential
        wraparound by adopting the reasonable assumption that the chain of
        increments from one to the other is shorter than 2**31.  So, if the
        difference between the two seqids is less than 2**31, then the
        lower seqid is to be treated as earlier.  If, however, the
        difference between the two seqids is greater than or equal to
        2**31, then it can be assumed that the lower seqid has encountered
        one more wraparound and can be treated as later.
      </t>
    </section>

    <section anchor="ss:fl:stateids" title="Stateid Definition">

      <t>
        When the server grants a lock of any type (including opens,
        byte-range locks, and delegations), it responds with a unique
        stateid that represents a set of locks (often a single lock) for the
        same file, of the same type, and sharing the same ownership
        characteristics.  Thus, opens of the same file by different
        open-owners each have an identifying stateid.  Similarly, each set of
        byte-range locks on a file owned by a specific lock-owner has its own
        identifying stateid.  Delegations also have associated
        stateids by which they may be referenced.  The stateid is used as a
        shorthand reference to a lock or set of locks, and given a stateid,
        the server can determine the associated state-owner or state-owners
        (in the case of an open-owner/lock-owner pair) and the associated
        filehandle.  When stateids are used, the current filehandle must be
        the one associated with that stateid.
      </t>

      <t>
        All stateids associated with a given client ID are associated with a
        common lease that represents the claim of those stateids and the
        objects they represent to be maintained by the server.  See
        <xref target="ss:fl:leaseren" /> for a discussion of the lease.
      </t>

      <t>
        Each stateid must be unique to the server.  Many operations take
        a stateid as an argument but not a clientid, so the server must
        be able to infer the client from the stateid.
      </t>

      <section anchor="stateid_types" title="Stateid Types">
        <t>
          With the exception of special stateids
          (see <xref target="ss:fl:special" />), each stateid
          represents locking objects of one of a set of types defined
          by the NFSv4 protocol.  Note that in all these cases, where
          we speak of a guarantee, it is understood there are
          situations such as a client restart, or lock revocation,
          that allow the guarantee to be voided.
          <list style='symbols'>
            <t>
              Stateids may represent opens of files.
              <vspace blankLines="1" />
              Each stateid in this case represents the OPEN state for a
              given client ID/open-owner/filehandle triple.  Such
              stateids are subject to change (with consequent
              incrementing of the stateid's seqid) in response to OPENs that
              result in upgrade and OPEN_DOWNGRADE operations.
            </t>
            <t>
              Stateids may represent sets of byte-range locks.
              <vspace blankLines="1" />
              All locks held on a particular file by a particular owner and all
              gotten under the aegis of a particular open file
              are associated with a single stateid, with the seqid
              being incremented whenever LOCK and LOCKU operations affect
              that set of locks.
            </t>
            <t>
              Stateids may represent file delegations, which are
              recallable guarantees by the server to the client
              that other clients will not reference, or will not
              modify, a particular file until the delegation is
              returned.
              <vspace blankLines="1" />
              A stateid represents a single delegation held by
              a client for a particular filehandle.
            </t>
          </list>
        </t>
      </section>

      <section anchor="ss:fl:ss" title="Stateid Structure">
        <t>
          Stateids are divided into two fields: a 96-bit "other" field
          identifying the specific set of locks and a 32-bit "seqid" sequence
          value.  Except in the case of special stateids (see <xref target="ss:fl:special" />), a
          particular value of the "other" field denotes a set of locks of the
          same type (for example, byte-range locks, opens, or delegations),
          for a specific file or directory, and sharing the same ownership
          characteristics.  The seqid designates a specific instance
          of such a set of locks, and is incremented to indicate changes in
          such a set of locks, by either the addition or deletion of locks
          from the set, a change in the byte-range they apply to, or
          an upgrade or downgrade in the type of one or more locks.
        </t>

        <t>
          When such a set of locks is first created, the server returns
          a stateid with a seqid value of one.  On subsequent operations that
          modify the set of locks, the server is required to advance the
          seqid field by one whenever it returns a stateid for the same
          state-owner/file/type combination and the operation is one that
          might make some change in the set
          of locks actually designated.  In this case, the server will return a
          stateid with an "other" field the same as previously used for that
          state-owner/file/type combination, with an incremented seqid field.
        </t>

        <t>
          Seqids will be compared, by both the client and the server.
          The client uses such comparisons to determine the order of
          operations, while the server uses them to determine
          whether the NFS4ERR_OLD_STATEID error is to be returned.
          In all cases, the possibility of seqid wraparound needs to be
          taken into account, as discussed in <xref target="ss:fl:seqids"/>.
        </t>
      </section>

      <section anchor="ss:fl:special" title="Special Stateids">
        <t>
          Stateid values whose "other" field is either all zeros or all
          ones are reserved.  They MUST NOT be assigned by the server but
          have special meanings defined by the protocol.  The particular
          meaning depends on whether the "other" field is all zeros or
          all ones and the specific value of the seqid field.
        </t>

        <t>
          The following combinations of "other" and seqid are defined
          in NFSv4:

          <list style='hanging'>
            <t hangText="Anonymous Stateid:">
              When "other" and seqid are both zero, the
              stateid is treated as a special anonymous
              stateid, which can be used in READ, WRITE,
              and SETATTR requests to indicate the absence
              of any open state associated with the
              request.  When an anonymous stateid value is
              used, and an existing open denies the form of
              access requested, then access will be denied
              to the request.
            </t>

            <t hangText="READ Bypass Stateid:">
              When "other" and seqid are both all ones,
              the stateid is a special READ bypass stateid.
              When this value is used in WRITE or SETATTR,
              it is treated like the anonymous value.
              When used in READ, the server MAY grant
              access, even if access would normally be
              denied to READ requests.
            </t>
          </list>
        </t>

        <t>
          If a stateid value is used that has all zeros or all ones in the
          "other" field but does not match one of the cases above, the
          server MUST return the error NFS4ERR_BAD_STATEID.
        </t>

        <t>
          Special stateids, unlike other stateids, are not associated with
          individual client IDs or filehandles and can be used with all valid
          client IDs and filehandles.
        </t>
      </section>

      <section anchor="stateid_lifetime" title="Stateid Lifetime and Validation">
        <t>
          Stateids must remain valid until either a client restart or a
          server restart, or until the client returns all of the locks
          associated with the stateid by means of an operation such as
          CLOSE or DELEGRETURN.  If the locks are lost due to revocation,
          as long as the client ID is valid, the stateid remains a
          valid designation of that revoked state. Stateids associated
          with byte-range locks are an exception.  They remain valid even if a
          LOCKU frees all remaining locks, so long as the open file with which
          they are associated remains open.
        </t>
        <t>
          It should be noted that there are situations in which the
          client's locks become invalid, without the client requesting
          they be returned.  These include lease expiration and a number
          of forms of lock revocation within the lease period.  It is
          important to note that in these situations, the stateid remains
          valid and the client can use it to determine the disposition of
          the associated lost locks.
        </t>
        <t>
          An "other" value must never be reused for a different purpose
          (i.e., different filehandle, owner, or type of locks) within the
          context of a single client ID.  A server may retain the "other"
          value for the same purpose beyond the point where it may otherwise
          be freed, but if it does so, it must maintain seqid continuity
          with previous values.
        </t>
        <t>
          One mechanism that may be used to satisfy the requirement that the
          server recognize invalid and out-of-date stateids is for
          the server to divide the "other" field of the stateid into two
          fields:
          <list style='symbols'>
            <t>
              An index into a table of locking-state structures.
            </t>
            <t>
              A generation number that is incremented on each allocation
              of a table entry for a particular use.
            </t>
          </list>
        </t>
        <t>
          And then store the following in each table entry:
          <list style='symbols'>
             <t>
               The client ID with which the stateid is associated.
             </t>
             <t>
               The current generation number for the (at most one)
               valid stateid sharing this index value.
             </t>
             <t>
               The filehandle of the file on which the locks are taken.
             </t>
             <t>
               An indication of the type of stateid (open, byte-range lock,
               file delegation).
             </t>
             <t>
               The last seqid value returned corresponding to the current
               "other" value.
             </t>
             <t>
               An indication of the current status of the locks
               associated with this stateid -- in particular, whether
               these have been revoked and, if so, for what reason.
             </t>
          </list>
        </t>
        <t>
          With this information, an incoming stateid can be validated and
          the appropriate error returned when necessary.  Special and
          non-special stateids are handled separately. (See
          <xref target='ss:fl:special' /> for a discussion of special
          stateids.)
        </t>
        <t>
          When a stateid is being tested,
          and the "other" field is all zeros or all ones, a check that
          the "other" and seqid fields match a defined combination for
          a special stateid is done and the results determined as follows:
          <list style='symbols'>
            <t>
              If the "other" and seqid fields do not match a defined
              combination associated with a special stateid, the error
              NFS4ERR_BAD_STATEID is returned.
            </t>
            <t>
              If the combination is valid in general but is not
              appropriate to the context in which the stateid is used
              (e.g., an all-zero stateid is used when an open stateid
              is required in a LOCK operation), the error
              NFS4ERR_BAD_STATEID is also returned.
            </t>
            <t>
              Otherwise, the check is completed and the special stateid
              is accepted as valid.
            </t>
          </list>
        </t>
        <t>
          When a stateid is being tested,
          and the "other" field is neither all zeros nor all ones, the
          following procedure could be used to
          validate an incoming stateid and return an appropriate error,
          when necessary, assuming that the "other" field would be divided
          into a table index and an entry generation.  Note that the
          terms "earlier" and "later" used in connection with seqid
          comparison are to be understood as explained in
          <xref target="ss:fl:seqids"/>.
          <list style='symbols'>
            <t>
              If the table index field is outside the range of the
              associated table, return NFS4ERR_BAD_STATEID.
            </t>
            <t>
              If the selected table entry is of a different generation than
              that specified in the incoming stateid, return
              NFS4ERR_BAD_STATEID.
            </t>
            <t>
              If the selected table entry does not match the current
              filehandle, return NFS4ERR_BAD_STATEID.
            </t>
            <t>
              If the stateid represents revoked state or state lost as a result
              of lease expiration, then return NFS4ERR_EXPIRED,
              NFS4ERR_BAD_STATEID, or NFS4ERR_ADMIN_REVOKED, as appropriate.
            </t>
            <t>
              If the stateid type is not valid for the context in which the
              stateid appears, return NFS4ERR_BAD_STATEID.
              Note that a stateid may be valid in general but invalid for
              a particular operation, as, for example, when a stateid
              that doesn't represent byte-range locks is passed to
              the non-from_open case of LOCK or to LOCKU, or when a stateid
              that does not represent an open is passed to CLOSE or
              OPEN_DOWNGRADE.  In such cases, the server MUST return
              NFS4ERR_BAD_STATEID.
            </t>
            <t>
              If the seqid field is not zero and it is later
              than the current sequence value corresponding to the
              current "other" field, return NFS4ERR_BAD_STATEID.
            </t>
            <t>
              If the seqid field is earlier than
              the current sequence value corresponding to the
              current "other" field, return NFS4ERR_OLD_STATEID.
            </t>
            <t>
              Otherwise, the stateid is valid, and the table entry
              should contain any additional information about the
              type of stateid and information associated with that
              particular type of stateid, such as the associated set
              of locks (e.g., open-owner and lock-owner information),
              as well as information on the specific locks themselves,
              such as open modes and byte ranges.
            </t>
          </list>
        </t>
      </section>

      <section anchor="ss:fl:sufioo" title="Stateid Use for I/O Operations">
        <t>
          Clients performing Input/Output (I/O) operations need to
          select an appropriate stateid based on the locks (including
          opens and delegations) held by the client and the various
          types of state-owners sending the I/O requests.  SETATTR
          operations that change the file size are treated like I/O
          operations in this regard.
        </t>

        <t>
          The following rules, applied in order of decreasing priority, govern
          the selection of the appropriate stateid.  In following these rules,
          the client will only consider locks of which it has actually received
          notification by an appropriate operation response or callback.

          <list style='symbols'>
            <t>
              If the client holds a delegation for the file in question, the
              delegation stateid SHOULD be used.
            </t>

            <t>
              Otherwise, if the entity corresponding to the lock-owner (e.g., a
              process) sending the I/O has a byte-range lock stateid for the
              associated open file, then the byte-range lock stateid for that
              lock-owner and open file SHOULD be used.
            </t>

            <t>
              If there is no byte-range lock stateid, then the OPEN stateid for
              the current open-owner, i.e., the OPEN stateid for the open
              file in question, SHOULD be used.
            </t>

            <t>
              Finally, if none of the above apply, then a special stateid SHOULD
              be used.
            </t>
          </list>
        </t>

        <t>
          Ignoring these rules may result in situations in which the server
          does not have information necessary to properly process the request.
          For example, when mandatory byte-range locks are in effect, if the
          stateid does not indicate the proper lock-owner, via a lock stateid,
          a request might be avoidably rejected.
        </t>

        <t>
          The server, however, should not try to enforce these ordering
          rules and should use whatever information is available to
          properly process I/O requests.  In particular, when a client
          has a delegation for a given file, it SHOULD take note of this
          fact in processing a request, even if it is sent with a
          special stateid.
        </t>
      </section>

      <section anchor="ss:fl:sufso" title="Stateid Use for SETATTR Operations">

        <t>
          In the case of SETATTR operations, a stateid is present.  In cases
          other than those that set the file size, the client may send either a
          special stateid or, when a delegation is held for the file in
          question, a delegation stateid.  While the server SHOULD validate the
          stateid and may use the stateid to optimize the determination as to
          whether a delegation is held, it SHOULD note the presence of a
          delegation even when a special stateid is sent, and MUST accept a
          valid delegation stateid when sent.
        </t>
      </section>

    </section>

    <section anchor="ss:fl:losd" title="Lock-Owner">

      <t>
        When requesting a lock, the client must present to the server the
        client ID and an identifier for the owner of the requested lock.
        These two fields comprise the lock-owner and are defined as follows:

        <list style='symbols'>
          <t>
            A client ID returned by the server as part of the client's use
            of the SETCLIENTID operation.
          </t>

          <t>
            A variable-length opaque array used to uniquely define the
            owner of a lock managed by the client.
          <vspace blankLines='1' />
            This may be a thread id, process id, or other unique value.
          </t>
        </list>
      </t>

      <t>
        When the server grants the lock, it responds with a unique stateid.
        The stateid is used as a shorthand reference to the lock-owner,
        since the server will be maintaining the correspondence between
        them.
      </t>
    </section>
    <section title="Use of the Stateid and Locking">

      <t>
        All READ, WRITE, and SETATTR operations contain a stateid.  For the
        purposes of this section, SETATTR operations that change the
        size attribute of a file are treated as if they are writing the
        area between the old and new size (i.e., the range truncated or
        added to the file by means of the SETATTR), even where SETATTR
        is not explicitly mentioned in the text. The stateid passed to
        one of these operations must be one that represents an OPEN (e.g.,
        via the open-owner), a set of byte-range locks, or a
        delegation, or it may be a special stateid representing anonymous
        access or the READ bypass stateid.
      </t>

      <t>
        If the state-owner performs a READ or WRITE in a situation in which
        it has established a lock or share reservation on the server (any
        OPEN constitutes a share reservation), the stateid (previously
        returned by the server) must be used to indicate what locks,
        including both byte-range locks and share reservations, are held by
        the state-owner.  If no state is established by the client -- either
        byte-range lock or share reservation -- the anonymous stateid is used.
        Regardless of whether an anonymous stateid or a stateid returned
        by the server is used, if there is a conflicting share reservation
        or mandatory byte-range lock held on the file, the server MUST refuse
        to service the READ or WRITE operation.
      </t>

      <t>
        Share reservations are established by OPEN operations and by
        their nature are mandatory in that when the OPEN denies READ
        or WRITE operations, that denial results in such operations
        being rejected with error NFS4ERR_LOCKED.  Byte-range locks may be
        implemented by the server as either mandatory or advisory, or
        the choice of mandatory or advisory behavior may be determined by
        the server on the basis of the file being accessed (for example,
        some UNIX-based servers support a "mandatory lock bit" on the
        mode attribute such that if set, byte-range locks are required on the
        file before I/O is possible).  When byte-range locks are advisory,
        they only prevent the granting of conflicting lock requests and
        have no effect on READs or WRITEs.  Mandatory byte-range locks,
        however, prevent conflicting I/O operations.  When they are
        attempted, they are rejected with NFS4ERR_LOCKED.  When the
        client gets NFS4ERR_LOCKED on a file it knows it has the proper
        share reservation for, it will need to issue a LOCK request on
        the region of the file that includes the region the I/O was to
        be performed on, with an appropriate locktype (i.e., READ*_LT
        for a READ operation, WRITE*_LT for a WRITE operation).
      </t>

      <t>
        With NFSv3, there was no notion of a stateid, so there was
        no way to tell if the application process of the client sending
        the READ or WRITE operation had also acquired the appropriate
        byte-range lock on the file.  Thus, there was no way to implement
        mandatory locking.  With the stateid construct, this barrier has
        been removed.
      </t>

      <t>
        Note that for UNIX environments that support mandatory file
        locking, the distinction between advisory and mandatory locking is
        subtle.  In fact, advisory and mandatory byte-range locks are exactly
        the same insofar as the APIs and requirements on implementation are
        concerned.
        If the mandatory lock attribute is set on the file, the server
        checks to see if the lock-owner has an appropriate shared (read)
        or exclusive (write) byte-range lock on the region it wishes to
        read or write to.  If there is no appropriate lock, the
        server checks if there is a conflicting lock (which can be done
        by attempting to acquire the conflicting lock on behalf of the
        lock-owner and, if successful, release the lock after the
        READ or WRITE is done), and if there is, the server returns
        NFS4ERR_LOCKED.
      </t>

      <t>
        For Windows environments, there are no advisory byte-range locks,
        so the server always checks for byte-range locks during I/O requests.
      </t>

      <t>
        Thus, the NFSv4 LOCK operation does not need to distinguish
        between advisory and mandatory byte-range locks.  It is the
        NFSv4 server's processing of the READ and WRITE operations
        that introduces the distinction.
      </t>

      <t>
        Every stateid other than the special stateid values noted in this
        section, whether returned by an OPEN-type operation (i.e., OPEN,
        OPEN_DOWNGRADE) or by a LOCK-type operation (i.e., LOCK or LOCKU),
        defines an access mode for the file (i.e., READ, WRITE, or
        READ-WRITE) as established by the original OPEN that began the stateid
        sequence, and as modified by subsequent OPENs and OPEN_DOWNGRADEs
        within that stateid sequence.  When a READ, WRITE, or SETATTR that
        specifies the size attribute is done, the operation is subject to
        checking against the access mode to verify that the operation is
        appropriate given the OPEN with which the operation is associated.
      </t>

      <t>
        In the case of WRITE-type operations (i.e., WRITEs and SETATTRs
        that set size), the server must verify that the access mode allows
        writing and return an NFS4ERR_OPENMODE error if it does not.
        In the case of READ, the server may perform the corresponding
        check on the access mode, or it may choose to allow READ on opens
        for WRITE only, to accommodate clients whose write implementation
        may unavoidably do reads (e.g., due to buffer cache constraints).
        However, even if READs are allowed in these circumstances,
        the server MUST still check for locks that conflict with the
        READ (e.g., another open specifying denial of READs).  Note that
        a server that does enforce the access mode check on READs need
        not explicitly check for conflicting share reservations since the
        existence of OPEN for read access guarantees that no conflicting
        share reservation can exist.
      </t>

      <t>
        A READ bypass stateid MAY allow READ operations to bypass
        locking checks at the server.  However, WRITE operations
        with a READ bypass stateid  MUST NOT bypass locking checks
        and are treated exactly the same as if an anonymous stateid
        were used.
      </t>

      <t>
        A lock may not be granted while a READ or WRITE operation using
        one of the special stateids is being performed and the range of
        the lock request conflicts with the range of the READ or WRITE
        operation.  For the purposes of this paragraph, a conflict occurs
        when a shared lock is requested and a WRITE operation is being
        performed, or an exclusive lock is requested and either a READ
        or a WRITE operation is being performed.  A SETATTR that sets
        size is treated similarly to a WRITE as discussed above.
      </t>

    </section>
    <section anchor="ss:fl:seqlock" title="Sequencing of Lock Requests">

      <t>
        Locking is different than most NFS operations as it requires
        "at&nbhy;most-one" semantics that are not provided by ONC RPC.
        ONC RPC over a reliable transport is not sufficient because a
        sequence of locking requests may span multiple TCP connections.
        In the face of retransmission or reordering, lock or unlock
        requests must have a well-defined and consistent behavior.
        To accomplish this, each lock request contains a sequence number
        that is a consecutively increasing integer.  Different state-owners
        have different sequences.  The server maintains the last sequence
        number (L) received and the response that was returned.  The server
        SHOULD assign a seqid value of one for the first request issued for any
        given state-owner.  Subsequent values are arrived at by incrementing
        the seqid value, subject to wraparound as described in
        <xref target="ss:fl:seqids" />.
      </t>

      <t>
        Note that for requests that contain a sequence number, for each
        state-owner, there should be no more than one outstanding request.
      </t>

      <t>
        When a request is received, its sequence number (r)
        is compared to that of the last one received (L).
        Only if it has the correct next sequence,
        normally L + 1, is the request processed beyond the point of
        seqid checking.  Given a properly functioning client, the
        response to (r) must have been received before the last request (L)
        was sent.  If a duplicate of last request (r == L) is received,
        the stored response is returned.  If the sequence value received
        is any other value, it is rejected with the return
        of error NFS4ERR_BAD_SEQID.  Sequence history is reinitialized
        whenever the SETCLIENTID/SETCLIENTID_CONFIRM sequence changes
        the client verifier.
      </t>

      <t>
        It is critical that the server maintain the last response sent to the
        client to provide a more reliable cache of duplicate non-idempotent
        requests than that of the traditional cache described in
        <xref target="Chet" />.  The traditional duplicate request cache
        uses a least recently used algorithm for removing unneeded
        requests.  However, the last lock request and response on a given
        state-owner must be cached as long as the lock state exists on the
        server.
      </t>

      <t>
        The client MUST advance  the sequence number for
        the CLOSE, LOCK, LOCKU, OPEN, OPEN_CONFIRM, and OPEN_DOWNGRADE
        operations.  This is true even in the event that the previous
        operation that used the sequence number received an error.
        The only exception to this rule is if the previous operation
        received one of the following errors: NFS4ERR_STALE_CLIENTID,
        NFS4ERR_STALE_STATEID, NFS4ERR_BAD_STATEID, NFS4ERR_BAD_SEQID,
        NFS4ERR_BADXDR, NFS4ERR_RESOURCE, NFS4ERR_NOFILEHANDLE,
        or NFS4ERR_MOVED.
      </t>

    </section>
    <section title="Recovery from Replayed Requests">

      <t>
        As described above, the sequence number is per state-owner.
        As long as the server maintains the last sequence number received
        and follows the methods described above, there are no risks of a
        Byzantine router re-sending old requests.  The server need only
        maintain the (state-owner, sequence number) state as long as there
        are open files or closed files with locks outstanding.
      </t>

      <t>
        LOCK, LOCKU, OPEN, OPEN_DOWNGRADE, and CLOSE each contain a
        sequence number, and therefore the risk of the replay of these
        operations resulting in undesired effects is non-existent while
        the server maintains the state-owner state.
      </t>

    </section>
    <section title="Interactions of Multiple Sequence Values">
      <t>
        Some operations may have multiple sources of data for request
        sequence checking and retransmission determination.  Some operations
        have multiple sequence values associated with multiple types of
        state-owners.  In addition, such operations may also have a stateid
        with its own seqid value, that will be checked for validity.
      </t>
      <t>
        As noted above, there may be multiple sequence values to check.
        The following rules should be followed by the server
        in processing these multiple sequence values
        within a single operation.
      <list style='symbols'>
        <t>
          When a sequence value associated with a state-owner is unavailable
          for checking because the state-owner is unknown to the
          server, it takes no part in the comparison.
        </t>
        <t>
          When any of the state-owner sequence values are invalid,
          NFS4ERR_BAD_SEQID is returned.  When a stateid sequence is checked,
          NFS4ERR_BAD_STATEID or NFS4ERR_OLD_STATEID is returned as
          appropriate, but NFS4ERR_BAD_SEQID has priority.
        </t>
        <t>
          When any one of the sequence values matches a previous request,
          for a state-owner, it is treated as a retransmission and not
          re&nbhy;executed.  When the type of the operation does not match that
          originally used, NFS4ERR_BAD_SEQID is returned.  When the
          server can determine that the request differs from the original,
          it may return NFS4ERR_BAD_SEQID.
        </t>
        <t>
          When multiple sequence values match previous operations but the
          operations are not the same, NFS4ERR_BAD_SEQID is returned.
        </t>
        <t>
          When there are no sequence values available for comparison
          and the operation is an OPEN, the server indicates
          to the client that an OPEN_CONFIRM is required, unless it can
          conclusively determine that confirmation is not required (e.g.,
          by knowing that no open-owner state has ever been released for the
          current clientid).
        </t>
      </list>
      </t>
    </section>
    <section title="Releasing State-Owner State">

      <t>
        When a particular state-owner no longer holds open or file
        locking state at the server, the server may choose to release
        the sequence number state associated with the state-owner.
        The server may make this choice based on lease expiration,
        the reclamation of server memory, or other
        implementation-specific details. Note that when this is done, a
        retransmitted request, normally identified by a matching
        state-owner sequence, may not be correctly recognized, so that
        the client will not receive the original response that it would
        have if the state-owner state was not released.
      </t>
      <t>
        If the server were able to be sure that a given state-owner would
        never again be used by a client, such an issue could not arise.
        Even when the state-owner state is released and the client
        subsequently uses that state-owner, retransmitted requests will be
        detected as invalid and the request not executed, although the
        client may have a recovery path that is more complicated than
        simply getting the original response back transparently.
      </t>
      <t>
        In any event, the server is able to safely release state-owner
        state (in the sense that retransmitted requests will not be erroneously
        acted upon) when the state-owner is not currently being utilized by
        the client (i.e., there are no open files associated with an
        open-owner and no lock stateids associated with a lock-owner).
        The server may choose
        to hold the state-owner state in order to simplify the recovery
        path, in the case in which retransmissions of currently active
        requests are received.  However, the period for which it
        chooses to hold this state is implementation specific.
      </t>
      <t>
        In the case that a LOCK, LOCKU, OPEN_DOWNGRADE, or CLOSE is
        retransmitted after the server has previously released the
        state-owner state, the server will find that the state-owner has no
        files open and an error will be returned to the client.  If the
        state-owner does have a file open, the stateid will not match and
        again an error is returned to the client.
      </t>

    </section>
    <section anchor="ss:fl:open_conf" title="Use of Open Confirmation">

      <t>
        In the case that an OPEN is retransmitted and the open-owner is
        being used for the first time or the open-owner state has been
        previously released by the server, the use of the OPEN_CONFIRM
        operation will prevent incorrect behavior.  When the server
        observes the use of the open-owner for the first time, it
        will direct the client to perform the OPEN_CONFIRM for the
        corresponding OPEN.  This sequence establishes the use of an
        open-owner and associated sequence number.  Since the OPEN_CONFIRM
        sequence connects a new open-owner on the server with an existing
        open-owner on a client, the sequence number may have any valid
        (i.e., non-zero) value.  The OPEN_CONFIRM step assures the
        server that the value received is the correct one.
        (See <xref target="OP_OPEN_CONFIRM" /> for further details.)
      </t>

      <t>
        There are a number of situations in which the requirement to
        confirm an OPEN would pose difficulties for the client and
        server, in that they would be prevented from acting in a timely
        fashion on information received, because that information would
        be provisional, subject to deletion upon non-confirmation.
        Fortunately, these are situations in which the server can avoid
        the need for confirmation when responding to open requests.
        The two constraints are:

        <list style='symbols'>
          <t>
            The server must not bestow a delegation for any open that
            would require confirmation.
          </t>

          <t>
            The server MUST NOT require confirmation on a reclaim-type
            open (i.e., one specifying claim type CLAIM_PREVIOUS or
            CLAIM_DELEGATE_PREV).
          </t>
        </list>
      </t>

      <t>
        These constraints are related in that reclaim-type opens are the
        only ones in which the server may be required to send a delegation.
        For CLAIM_NULL, sending the delegation is optional, while for
        CLAIM_DELEGATE_CUR, no delegation is sent.
      </t>

      <t>
        Delegations being sent with an open requiring confirmation are
        troublesome because recovering from non-confirmation adds undue
        complexity to the protocol, while requiring confirmation on
        reclaim-type opens poses difficulties in that the inability to
        resolve the status of the reclaim until lease expiration may
        make it difficult to have timely determination of the set of
        locks being reclaimed (since the grace period may expire).
      </t>

      <t>
        Requiring open confirmation on reclaim-type opens is avoidable
        because of the nature of the environments in which such opens are
        done.  For CLAIM_PREVIOUS opens, this is immediately after server
        reboot, so there should be no time for open-owners to be created,
        found to be unused, and recycled.  For CLAIM_DELEGATE_PREV opens, we
        are dealing with either a client reboot situation or a network
        partition resulting in deletion of lease state (and
        returning NFS4ERR_EXPIRED). A server that supports delegations
        can be sure that no open-owners for that client have been
        recycled since client initialization or deletion of lease state
        and thus can be confident that confirmation will not be required.
      </t>
    </section>
  </section>
  <section title="Lock Ranges">

    <t>
      The protocol allows a lock-owner to request a lock with a byte
      range and then either upgrade or unlock a sub-range of the
      initial lock.  It is expected that this will be an uncommon type
      of request.  In any case, servers or server file systems may not be
      able to support sub&nbhy;range lock semantics.  In the event that a
      server receives a locking request that represents a sub&nbhy;range of
      current locking state for the lock-owner, the server is allowed
      to return the error NFS4ERR_LOCK_RANGE to signify that it does
      not support sub&nbhy;range lock operations.  Therefore, the client
      should be prepared to receive this error and, if appropriate,
      report the error to the requesting application.
    </t>

    <t>
      The client is discouraged from combining multiple independent
      locking ranges that happen to be adjacent into a single request,
      since the server may not support sub-range requests, and for reasons
      related to the recovery of file locking state in the event of
      server failure.  As discussed in <xref target="ss:fl:sfr" />
      below, the server may employ certain optimizations
      during recovery that work effectively only when the client's
      behavior during lock recovery is similar to the client's locking
      behavior prior to server failure.
    </t>

  </section>
  <section title="Upgrading and Downgrading Locks">

    <t>
      If a client has a write lock on a record, it can request an
      atomic downgrade of the lock to a read lock via the LOCK request,
      by setting the type to READ_LT.  If the server supports atomic
      downgrade, the request will succeed.  If not, it will return
      NFS4ERR_LOCK_NOTSUPP.  The client should be prepared to receive
      this error and, if appropriate, report the error to the requesting
      application.
    </t>

    <t>
      If a client has a read lock on a record, it can request an
      atomic upgrade of the lock to a write lock via the LOCK request
      by setting the type to WRITE_LT or WRITEW_LT.  If the server does
      not support atomic upgrade, it will return NFS4ERR_LOCK_NOTSUPP.
      If the upgrade can be achieved without an existing conflict, the
      request will succeed.  Otherwise, the server will return either
      NFS4ERR_DENIED or NFS4ERR_DEADLOCK.  The error NFS4ERR_DEADLOCK is
      returned if the client issued the LOCK request with the type set
      to WRITEW_LT and the server has detected a deadlock.  The client
      should be prepared to receive such errors and, if appropriate,
      report them to the requesting application.
    </t>

  </section>
  <section anchor="sec:blocklock" title="Blocking Locks">

    <t>
      Some clients require the support of blocking locks.  The
      NFSv4 protocol must not rely on a callback mechanism and
      therefore is unable to notify a client when a previously denied
      lock has been granted.  Clients have no choice but to continually
      poll for the lock.  This presents a fairness problem.  Two new
      lock types are added, READW and WRITEW, and are used to indicate
      to the server that the client is requesting a blocking lock.
      The server should maintain an ordered list of pending blocking
      locks.  When the conflicting lock is released, the server may
      wait the lease period for the first waiting client to re-request
      the lock.  After the lease period expires, the next waiting client
      request is allowed the lock.  Clients are required to poll at
      an interval sufficiently small that it is likely to acquire the
      lock in a timely manner.  The server is not required to maintain a
      list of pending blocked locks, as it is not used to provide correct
      operation but only to increase fairness.  Because of the unordered
      nature of crash recovery, storing of lock state to stable storage
      would be required to guarantee ordered granting of blocking locks.
    </t>

    <t>
      Servers may also note the lock types and delay returning denial
      of the request to allow extra time for a conflicting lock to be
      released, allowing a successful return.  In this way, clients can
      avoid the burden of needlessly frequent polling for blocking locks.
      The server should take care with the length of delay in the event
      that the client retransmits the request.
    </t>

    <t>
      If a server receives a blocking lock request, denies it, and then
      later receives a non-blocking request for the same lock, which is also
      denied, then it should remove the lock in question from its list of
      pending blocking locks.  Clients should use such a non-blocking
      request to indicate to the server that this is the last time they
      intend to poll for the lock, as may happen when the process
      requesting the lock is interrupted.  This is a courtesy to the
      server, to prevent it from unnecessarily waiting a lease period
      before granting other lock requests.  However, clients are not
      required to perform this courtesy, and servers must not depend on
      them doing so.  Also, clients must be prepared for the possibility
      that this final locking request will be accepted.
    </t>

  </section>
  <section anchor="ss:fl:leaseren" title="Lease Renewal">

    <t>
      The purpose of a lease is to allow a server to remove stale
      locks that are held by a client that has crashed or is otherwise
      unreachable.  It is not a mechanism for cache consistency, and
      lease renewals may not be denied if the lease interval has not expired.
    </t>

    <t>
      The client can implicitly provide a positive indication that it is
      still active and that the associated state held at the server, for
      the client, is still valid.  Any operation made with a valid clientid
      (DELEGPURGE, LOCK, LOCKT, OPEN, RELEASE_LOCKOWNER, or RENEW) or a
      valid stateid (CLOSE, DELEGRETURN, LOCK, LOCKU, OPEN, OPEN_CONFIRM,
      OPEN_DOWNGRADE, READ, SETATTR, or WRITE) informs the server to renew
      all of the leases for that client (i.e., all those sharing a given
      client ID).  In the latter case, the stateid must not be one of the
      special stateids (anonymous stateid or READ bypass stateid).
    </t>

    <t>
      Note that if the client had restarted or rebooted, the
      client would not be making these requests without issuing
      the SETCLIENTID/SETCLIENTID_CONFIRM sequence.  The use of the
      SETCLIENTID/SETCLIENTID_CONFIRM sequence (one that changes the
      client verifier) notifies the server to drop the locking state
      associated with the client.  SETCLIENTID/SETCLIENTID_CONFIRM
      never renews a lease.
    </t>

    <t>
      If the server has rebooted, the stateids (NFS4ERR_STALE_STATEID
      error) or the client ID (NFS4ERR_STALE_CLIENTID error) will
      not be valid, hence preventing spurious renewals.
    </t>

    <t>
      This approach allows for low-overhead lease renewal, which scales
      well.  In the typical case, no extra RPCs are required for
      lease renewal, and in the worst case, one RPC is required every
      lease period (i.e., a RENEW operation).  The number of locks held
      by the client is not a factor since all state for the client is
      involved with the lease renewal action.
    </t>

    <t>
      Since all operations that create a new lease also renew existing
      leases, the server must maintain a common lease expiration time
      for all valid leases for a given client.  This lease time can
      then be easily updated upon implicit lease renewal actions.
    </t>

  </section>
  <section anchor="ss:fl:crash_recov" title="Crash Recovery">

    <t>
      The important requirement in crash recovery is that both the client
      and the server know when the other has failed.  Additionally, it
      is required that a client sees a consistent view of data across
      server restarts or reboots.  All READ and WRITE operations that may
      have been queued within the client or network buffers must wait
      until the client has successfully recovered the locks protecting
      the READ and WRITE operations.
    </t>

    <section title="Client Failure and Recovery">

      <t>
        In the event that a client fails, the server may recover
        the client's locks when the associated leases have expired.
        Conflicting locks from another client may only be granted after
        this lease expiration.  If the client is able to restart or
        reinitialize within the lease period, the client may be forced to
        wait the remainder of the lease period before obtaining new locks.
      </t>

      <t>
        To minimize client delay upon restart, open and lock requests are
        associated with an instance of the client by a client-supplied
        verifier.
        This verifier is part of the initial SETCLIENTID call made by
        the client.  The server returns a client ID as a result of the
        SETCLIENTID operation.  The client then confirms the use of the
        client ID with SETCLIENTID_CONFIRM.  The client ID in combination
        with an opaque owner field is then used by the client to identify
        the open-owner for OPEN.  This chain of associations is then used
        to identify all locks for a particular client.
      </t>

      <t>
        Since the verifier will be changed by the client upon each
        initialization, the server can compare a new verifier to the
        verifier associated with currently held locks and determine that
        they do not match.  This signifies the client's new instantiation
        and subsequent loss of locking state.  As a result, the server
        is free to release all locks held that are associated with the
        old client ID that was derived from the old verifier.
      </t>

      <t>
        Note that the verifier must have the same uniqueness properties
        of the verifier for the COMMIT operation.
      </t>

    </section>
    <section anchor="ss:fl:sfr" title="Server Failure and Recovery">

      <t>
        If the server loses locking state (usually as a result of a restart
        or reboot), it must allow clients time to discover this fact and
        re&nbhy;establish the lost locking state.  The client must be able
        to re&nbhy;establish the locking state without having the server deny
        valid requests because the server has granted conflicting access
        to another client.  Likewise, if there is the possibility that
        clients have not yet re&nbhy;established their locking state for a file,
        the server must disallow READ and WRITE operations for that file.
        The duration of this recovery period is equal to the duration of
        the lease period.
      </t>

      <t>
        A client can determine that server failure (and thus loss of
        locking state) has occurred, when it receives one of two errors.
        The NFS4ERR_STALE_STATEID error indicates a stateid invalidated by
        a reboot or restart.  The NFS4ERR_STALE_CLIENTID error indicates
        a client ID invalidated by reboot or restart.  When either of
        these is received, the client must establish a new client ID
        (see <xref target="ss:fl:client_id" />) and re-establish the
        locking state as discussed below.
      </t>

      <t>
        The period of special handling of locking and READs and WRITEs,
        equal in duration to the lease period, is referred to as the
        "grace period".  During the grace period, clients recover locks
        and the associated state by reclaim-type locking requests (i.e.,
        LOCK requests with reclaim set to TRUE and OPEN operations with
        a claim type of either CLAIM_PREVIOUS or CLAIM_DELEGATE_PREV).
        During the grace period, the server must reject READ and WRITE
        operations and non-reclaim locking requests (i.e., other LOCK
        and OPEN operations) with an error of NFS4ERR_GRACE.
      </t>

      <t>
        If the server can reliably determine that granting a non-reclaim
        request will not conflict with reclamation of locks by other
        clients, the NFS4ERR_GRACE error does not have to be returned
        and the non&nbhy;reclaim client request can be serviced.  For the
        server to be able to service READ and WRITE operations during the
        grace period, it must again be able to guarantee that no possible
        conflict could arise between an impending reclaim locking request
        and the READ or WRITE operation.  If the server is unable to
        offer that guarantee, the NFS4ERR_GRACE error must be returned
        to the client.
      </t>

      <t>
        For a server to provide simple, valid handling during the grace
        period, the easiest method is to simply reject all non-reclaim
        locking requests and READ and WRITE operations by returning the
        NFS4ERR_GRACE error.  However, a server may keep information
        about granted locks in stable storage.  With this information,
        the server could determine if a regular lock or READ or WRITE
        operation can be safely processed.
      </t>

      <t>
        For example, if a count of locks on a given file is available in
        stable storage, the server can track reclaimed locks for the file,
        and when all reclaims have been processed, non-reclaim locking
        requests may be processed.  This way, the server can ensure that
        non&nbhy;reclaim locking requests will not conflict with potential
        reclaim requests.  With respect to I/O requests, if the server is
        able to determine that there are no outstanding reclaim requests
        for a file by information from stable storage or another similar
        mechanism, the processing of I/O requests could proceed normally
        for the file.
      </t>

      <t>
        To reiterate, for a server that allows non-reclaim lock and
        I/O requests to be processed during the grace period, it MUST
        determine that no lock subsequently reclaimed will be rejected
        and that no lock subsequently reclaimed would have prevented any
        I/O operation processed during the grace period.
      </t>

      <t>
        Clients should be prepared for the return of NFS4ERR_GRACE errors
        for non-reclaim lock and I/O requests.  In this case, the client
        should employ a retry mechanism for the request.  A delay (on the
        order of several seconds) between retries should be used to avoid
        overwhelming the server.  Further discussion of the general issue
        is included in <xref target="Floyd" />.  The client must account
        for the server that is able to perform I/O and non-reclaim
        locking requests within the grace period as well as those that
        cannot do so.
      </t>

      <t>
        A reclaim-type locking request outside the server's grace period
        can only succeed if the server can guarantee that no conflicting
        lock or I/O request has been granted since reboot or restart.
      </t>

      <t>
        A server may, upon restart, establish a new value for the
        lease period.  Therefore, clients should, once a new client ID is
        established, refetch the lease_time attribute and use it as the
        basis for lease renewal for the lease associated with that server.
        However, the server must establish, for this restart event, a
        grace period at least as long as the lease period for the previous
        server instantiation.  This allows the client state obtained
        during the previous server instance to be reliably re-established.
      </t>
    </section>

    <section title="Network Partitions and Recovery">
      <t>
        If the duration of a network partition is greater than the lease
        period provided by the server, the server will have not received
        a lease renewal from the client.  If this occurs, the server may
        cancel the lease and
        free all locks held for the client.  As a result, all stateids
        held by the client will become invalid or stale.  Once the client
        is able to reach the server after such a network partition,
        all I/O submitted by the client with the now invalid stateids
        will fail with the server returning the error NFS4ERR_EXPIRED.
        Once this error is received, the client will suitably notify the
        application that held the lock.
      </t>

      <section anchor="ss:fl:cl" title="Courtesy Locks">
        <t>
          As a courtesy to the client or as an optimization, the server may
          continue to hold locks, including delegations, on behalf of a client
          for which recent communication has extended beyond the lease period,
          delaying the cancellation of the lease.  If the server receives a lock
          or I/O request that conflicts with one of these courtesy locks or if it
          runs out of resources, the server MAY cause lease cancellation to occur at
          that time and henceforth return NFS4ERR_EXPIRED when any of the stateids
          associated with the freed locks is used. If lease cancellation has not
          occurred and the server receives a lock or I/O request that conflicts with
          one of the courtesy locks, the requirements are as follows:

          <list style='symbols'>
            <t>
              In the case of a courtesy lock that is not a delegation,
              it MUST free the courtesy lock and grant the new request.
            </t>

            <t>
              In the case of a lock or an I/O request that conflicts with a
              delegation that is being held as a courtesy lock, the server
              MAY delay resolution of the request but MUST NOT reject the
              request and MUST free the delegation and grant the new
              request eventually.
            </t>

            <t>
              In the case of a request for a delegation that conflicts with a
              delegation that is being held as a courtesy lock, the server MAY
              grant the new request or not as it chooses, but if it grants the
              conflicting request, the delegation held as a courtesy lock
              MUST be freed.
            </t>
          </list>
        </t>

        <t>
          If the server does not reboot or cancel the lease before the network
          partition is healed, when the original client tries to access a courtesy
          lock that was freed, the server SHOULD send back an NFS4ERR_BAD_STATEID
          to the client.  If the client tries to access a courtesy lock that
          was not freed, then the server SHOULD mark all of the courtesy locks as
          implicitly being renewed.
        </t>
      </section>

      <section anchor="ss:fl:lc" title="Lease Cancellation">
        <t>
          As a result of lease expiration, leases may be canceled, either
          immediately upon expiration or subsequently, depending on the occurrence
          of a conflicting lock or extension of the period of partition beyond
          what the server will tolerate.
        </t>

        <t>
          When a lease is canceled, all locking state associated with it is
          freed, and the use of any of the associated stateids will result in
          NFS4ERR_EXPIRED being returned.  Similarly, the use of the
          associated clientid will result in NFS4ERR_EXPIRED being returned.
        </t>

        <t>
          The client should recover from this situation by using SETCLIENTID
          followed by SETCLIENTID_CONFIRM, in order to establish a new
          clientid. Once a lock is obtained using this clientid, a lease
          will be established.
        </t>
      </section>

      <section title="Client's Reaction to a Freed Lock">
        <t>
          There is no way for a client to predetermine how a given server
          is going to behave during a network partition. When the
          partition heals, the client still has either all of its locks,
          some of its locks, or none of them. The client will be able to
          examine the various error return values to determine its response.

            <list style="hanging">
              <t hangText="NFS4ERR_EXPIRED:"> <vspace blankLines='1' />
                All locks have been freed as a result of a lease cancellation
                that occurred during the partition.  The client should use a
                SETCLIENTID to recover.
              </t>

              <t hangText="NFS4ERR_ADMIN_REVOKED:"> <vspace blankLines='1' />
                The current lock has been revoked before, during, or after
                the partition.  The client SHOULD handle this error
                as it normally would.
              </t>

              <t hangText="NFS4ERR_BAD_STATEID:"> <vspace blankLines='1' />
                The current lock has been revoked/released during the
                partition, and the server did not reboot.  Other locks
                MAY still be renewed.  The client need not do a
                SETCLIENTID and instead SHOULD probe via a RENEW call.
              </t>

              <t hangText="NFS4ERR_RECLAIM_BAD:"> <vspace blankLines='1' />
                The current lock has been revoked during the partition, and
                the server rebooted. The server might have no information
                on the other locks. They may still be renewable.
              </t>

              <t hangText="NFS4ERR_NO_GRACE:"> <vspace blankLines='1' />
                The client's locks have been revoked during the partition, and
                the server rebooted. None of the client's locks will be
                renewable.
              </t>

              <t hangText="NFS4ERR_OLD_STATEID:"> <vspace blankLines='1' />
                The server has not rebooted. The client SHOULD handle
                this error as it normally would.
              </t>
            </list>
          </t>
      </section>

      <section anchor="ss:fl:edges" title="Edge Conditions">
        <t>
          When a network partition is combined with a server reboot, then
          both the server and client have responsibilities to ensure that
          the client does not reclaim a lock that it should no longer
          be able to access. Briefly, those are:

          <list style='symbols'>
            <t>
              Client's responsibility: A client MUST NOT attempt to
              reclaim any locks that it did not hold at the end of
              its most recent successfully established client lease.
            </t>

            <t>
              Server's responsibility: A server MUST NOT allow a
              client to reclaim a lock unless it knows that it could
              not have since granted a conflicting lock.  However, in
              deciding whether a conflicting lock could have been
              granted, it is permitted to assume that its clients are
              responsible, as above.
            </t>
          </list>
        </t>

        <t>
          A server may consider a client's lease "successfully
          established" once it has received an OPEN operation from that
          client.
        </t>

        <t>
          The above are directed to CLAIM_PREVIOUS reclaims and not to
          CLAIM_DELEGATE_PREV reclaims, which generally do not involve
          a server reboot.  However, when a server persistently stores
          delegation information to support CLAIM_DELEGATE_PREV across
          a period in which both client and server are down at the same
          time, similar strictures apply.
        </t>

        <t>
          The next sections give examples showing what can go wrong if
          these responsibilities are neglected and also provide examples of
          server implementation strategies that could meet a server's
          responsibilities.
        </t>

        <section title="First Server Edge Condition">
          <t>
            The first edge condition has the following scenario:

            <list style='numbers'>
              <t>
                Client A acquires a lock.
              </t>

              <t>
                Client A and the server experience mutual network partition,
                such that client A is unable to renew its lease.
              </t>

              <t>
                Client A's lease expires, so the server releases the lock.
              </t>

              <t>
                Client B acquires a lock that would have conflicted with
                that of client A.
              </t>

              <t>
                Client B releases the lock.
              </t>

              <t>
                The server reboots.
              </t>

              <t>
                The network partition between client A and the server heals.
              </t>

              <t>
                Client A issues a RENEW operation and gets back an
                NFS4ERR_STALE_CLIENTID.
              </t>

              <t>
                Client A reclaims its lock within the server's grace period.
              </t>
            </list>
          </t>

          <t>
            Thus, at the final step, the server has erroneously granted
            client&nbsp;A's lock reclaim.  If client B modified the
            object the lock was protecting, client A will experience
            object corruption.
          </t>
        </section>

        <section title="Second Server Edge Condition">
          <t>
            The second known edge condition follows:

            <list style='numbers'>

              <t>
                Client A acquires a lock.
              </t>

              <t>
                The server reboots.
              </t>

              <t>
                Client A and the server experience mutual network partition,
                such that client A is unable to reclaim its lock within
                the grace period.
              </t>

              <t>
                The server's reclaim grace period ends.  Client A has no locks
                recorded on the server.
              </t>

              <t>
                Client B acquires a lock that would have conflicted with
                that of client A.
              </t>

              <t>
                Client B releases the lock.
              </t>

              <t>
                The server reboots a second time.
              </t>

              <t>
                The network partition between client A and the server heals.
              </t>

              <t>
                Client A issues a RENEW operation and gets back an
                NFS4ERR_STALE_CLIENTID.
              </t>

              <t>
                Client A reclaims its lock within the server's grace period.
              </t>
            </list>
          </t>

          <t>
            As with the first edge condition, the final step of the scenario
            of the second edge condition has the server erroneously granting
            client&nbsp;A's lock reclaim.
          </t>
        </section>

        <section title="Handling Server Edge Conditions">
          <t>
            In both of the above examples, the client attempts reclaim
            of a lock that it held at the end of its most recent
            successfully established lease; thus, it has fulfilled its
            responsibility.
          </t>

          <t>
            The server, however, has failed, by granting a reclaim,
            despite having granted a conflicting lock since the
            reclaimed lock was last held.
          </t>

          <t>
            Solving these edge conditions requires that the
            server either (1) assume after it reboots that an edge condition
            occurs, and thus return NFS4ERR_NO_GRACE for all reclaim
            attempts, or (2) record some information in stable storage.
            The amount
            of information the server records in stable storage is in inverse
            proportion to how harsh the server wants to be whenever the edge
            conditions occur.  The server that is completely tolerant of all
            edge conditions will record in stable storage every lock that
            is acquired, removing the lock record from stable storage only
            when the lock is unlocked by the client and the lock's owner
            advances the sequence number such that the lock release is not
            the last stateful event for the owner's sequence.  For the two
            aforementioned edge conditions, the harshest a server can be, and
            still support a grace period for reclaims, requires that the server
            record in stable storage some minimal information.
            For example, a server implementation could, for each client,
            save in stable storage a record containing:

            <list style='symbols'>
              <t>
                the client's id string.
              </t>

              <t>
                a boolean that indicates if the client's lease expired or
                if there was administrative intervention (see
                <xref target="ss:fl:srl" />) to revoke a byte-range lock,
                share reservation, or delegation.
              </t>

              <t>
                a timestamp that is updated the first time after a server boot
                or reboot the client acquires byte-range locking, share reservation,
                or delegation state on the server.  The timestamp need not be
                updated on subsequent lock requests until the server reboots.
              </t>
            </list>
          </t>

          <t>
            The server implementation would also record in stable storage
            the timestamps from the two most recent server reboots.
          </t>

          <t>
            Assuming the above record keeping, for the first edge condition,
            after the server reboots, the record that client A's lease expired
            means that another client could have acquired a conflicting record
            lock, share reservation, or delegation.  Hence, the server must
            reject a reclaim from client A with the error NFS4ERR_NO_GRACE or
            NFS4ERR_RECLAIM_BAD.
          </t>

          <t>
            For the second edge condition, after the server reboots for a
            second time, the record that the client had an unexpired record
            lock, share reservation, or delegation established before the
            server's previous incarnation means that the server must reject
            a reclaim from client A with the error NFS4ERR_NO_GRACE or
            NFS4ERR_RECLAIM_BAD.
          </t>

          <t>
            Regardless of the level and approach to record keeping, the server
            MUST implement one of the following strategies (which apply to
            reclaims of share reservations, byte-range locks, and delegations):

            <list style='numbers'>
              <t>
                Reject all reclaims with NFS4ERR_NO_GRACE.  This is
                extremely harsh but is necessary if the server does not
                want to record lock state in stable storage.
              </t>

              <t>
                Record sufficient state in stable storage to meet its
                responsibilities.  In doubt, the server should err on
                the side of being harsh.
                <vspace blankLines="1"/>
                In the event that, after a server reboot, the server
                determines that there is unrecoverable damage or corruption
                to stable storage, then for all clients and/or locks
                affected, the server MUST return NFS4ERR_NO_GRACE.
              </t>
            </list>
          </t>
        </section>

        <section title="Client Edge Condition">
          <t>
            A third edge condition affects the client and not the server.
            If the server reboots in the middle of the client reclaiming
            some locks and then a network partition is established, the
            client might be in the situation of having reclaimed some, but
            not all, locks. In that case, a conservative client would
            assume that the non-reclaimed locks were revoked.
          </t>

          <t>
            The third known edge condition follows:

            <list style='numbers'>

              <t>
                Client A acquires a lock 1.
              </t>

              <t>
                Client A acquires a lock 2.
              </t>

              <t>
                The server reboots.
              </t>

              <t>
                Client A issues a RENEW operation and gets back an
                NFS4ERR_STALE_CLIENTID.
              </t>

              <t>
                Client A reclaims its lock 1 within the server's grace period.
              </t>

              <t>
                Client A and the server experience mutual network partition,
                such that client A is unable to reclaim its remaining locks
                within the grace period.
              </t>

              <t>
                The server's reclaim grace period ends.
              </t>

              <t>
                Client B acquires a lock that would have conflicted
                with client&nbsp;A's lock 2.
              </t>

              <t>
                Client B releases the lock.
              </t>

              <t>
                The server reboots a second time.
              </t>

              <t>
                The network partition between client A and the server heals.
              </t>

              <t>
                Client A issues a RENEW operation and gets back an
                NFS4ERR_STALE_CLIENTID.
              </t>

              <t>
                Client A reclaims both lock 1 and lock 2 within the
                server's grace period.
              </t>
            </list>
          </t>

          <t>
            At the last step, the client reclaims lock 2 as if it had
            held that lock continuously, when in fact a conflicting lock
            was granted to client B.
          </t>

          <t>
            This occurs because the client failed its responsibility, by
            attempting to reclaim lock 2 even though it had not held
            that lock at the end of the lease that was established by
            the SETCLIENTID after the first server reboot.  (The client
            did hold lock 2 on a previous lease, but it is only the most
            recent lease that matters.)
          </t>

          <t>
            A server could avoid this situation by rejecting the reclaim
            of lock&nbsp;2.  However, to do so accurately, it would have to
            ensure that additional information about individual locks
            held survives a reboot.  Server implementations are not
            required to do that, so the client must not assume that the
            server will.
          </t>

          <t>
            Instead, a client MUST reclaim only those locks that it
            successfully acquired from the previous server instance, omitting
            any that it failed to reclaim before a new reboot.  Thus, in the
            last step above, client A should reclaim only lock 1.
          </t>
        </section>

        <section title="Client's Handling of Reclaim Errors">
          <t>
            A mandate for the client's handling of the NFS4ERR_NO_GRACE
            and NFS4ERR_RECLAIM_BAD errors is outside the scope of this
            specification, since the strategies for such handling are
            very dependent on the client's operating environment.
            However, one potential approach is described below.
          </t>

          <t>
            When the client's reclaim fails, it could examine
            the change attribute of the objects the client is trying
            to reclaim state for, and use that to determine whether
            to re-establish the state via normal OPEN or LOCK requests.
            This is acceptable, provided the client's operating environment
            allows it.  In other words, the client implementer is advised
            to document the behavior for his users.  The client could also
            inform the application that its byte-range lock or share
            reservations (whether they were delegated or not) have been
            lost, such as via a UNIX signal, a GUI pop-up window, etc.
            See <xref target="ss:cc:cache_revoke" /> for a discussion of
            what the client should do for dealing with unreclaimed
            delegations on client state.
          </t>

          <t>
            For further discussion of revocation of locks,
            see <xref target="ss:fl:srl" />.
          </t>
        </section>
      </section>
    </section>
  </section>

  <section title="Recovery from a Lock Request Timeout or Abort">
    <t>
      In the event a lock request times out, a client may decide to
      not retry the request.  The client may also abort the request
      when the process for which it was issued is terminated (e.g.,
      in UNIX due to a signal).  It is possible, though, that the server
      received the request and acted upon it.  This would change the
      state on the server without the client being aware of the change.
      It is paramount that the client resynchronize state with the server
      before it attempts any other operation that takes a seqid and/or
      a stateid with the same state-owner.  This is straightforward to
      do without a special resynchronize operation.
    </t>

    <t>
      Since the server maintains the last lock request and response
      received on the state-owner, for each state-owner, the client should
      cache the last lock request it sent such that the lock request did
      not receive a response.  From this, the next time the client does a
      lock operation for the state-owner, it can send the cached request,
      if there is one, and if the request was one that established state
      (e.g., a LOCK or OPEN operation), the server will return the cached
      result or, if it never saw the request, perform it.  The client can
      follow up with a request to remove the state (e.g., a LOCKU or
      CLOSE operation).  With this approach, the sequencing and stateid
      information on the client and server for the given state-owner
      will resynchronize, and in turn the lock state will resynchronize.
    </t>
  </section>

  <section anchor="ss:fl:srl" title="Server Revocation of Locks">
    <t>
      At any point, the server can revoke locks held by a client and the
      client must be prepared for this event.  When the client detects
      that its locks have been or may have been revoked, the client is
      responsible for validating the state information between itself
      and the server.  Validating locking state for the client means
      that it must verify or reclaim state for each lock currently held.
    </t>

    <t>
      The first instance of lock revocation is upon server reboot or
      re&nbhy;initialization.  In this instance, the client will receive an
      error (NFS4ERR_STALE_STATEID or NFS4ERR_STALE_CLIENTID) and the
      client will proceed with normal crash recovery as described in
      the previous section.
    </t>

    <t>
      The second lock revocation event is the inability to renew the
      lease before expiration.  While this is considered a rare or
      unusual event, the client must be prepared to recover.  Both the
      server and client will be able to detect the failure to renew
      the lease and are capable of recovering without data corruption.
      For the server, it tracks the last renewal event serviced for
      the client and knows when the lease will expire.  Similarly, the
      client must track operations that will renew the lease period.
      Using the time that each such request was sent and the time that
      the corresponding reply was received, the client should bound the
      time that the corresponding renewal could have occurred on the
      server and thus determine if it is possible that a lease period
      expiration could have occurred.
    </t>

    <t>
      The third lock revocation event can occur as a result of
      administrative intervention within the lease period.  While this
      is considered a rare event, it is possible that the server's
      administrator has decided to release or revoke a particular lock
      held by the client.  As a result of revocation, the client will
      receive an error of NFS4ERR_ADMIN_REVOKED.  In this instance, the
      client may assume that only the state-owner's locks have been lost.
      The client notifies the lock holder appropriately.  The client
      cannot assume that the lease period has been renewed as a result of
      a failed operation.
    </t>

    <t>
      When the client determines the lease period may have expired,
      the client must mark all locks held for the associated lease
      as "unvalidated".  This means the client has been unable
      to re-establish or confirm the appropriate lock state with the
      server.  As described in <xref target="ss:fl:crash_recov" />,
      there are scenarios in which the server may grant conflicting
      locks after the lease period has expired for a client.  When it
      is possible that the lease period has expired, the client must
      validate each lock currently held to ensure that a conflicting
      lock has not been granted.  The client may accomplish this task by
      issuing an I/O request; if there is no relevant I/O pending,
      a zero-length read specifying the stateid associated with the lock
      in question can be synthesized to trigger the renewal.
      If the response to the request is success, the client has validated
      all of the locks governed by that stateid and re-established the
      appropriate state between itself and the server.
    </t>

    <t>
      If the I/O request is not successful, then one or more of the
      locks associated with the stateid were revoked by the server, and
      the client must notify the owner.
    </t>

  </section>
  <section anchor="ss:fl:share_res" title="Share Reservations">

    <t>
      A share reservation is a mechanism to control access to a file.
      It is a separate and independent mechanism from byte-range locking.
      When a client opens a file, it issues an OPEN operation to the
      server specifying the type of access required (READ, WRITE, or
      BOTH) and the type of access to deny others (OPEN4_SHARE_DENY_NONE,
      OPEN4_SHARE_DENY_READ, OPEN4_SHARE_DENY_WRITE, or
      OPEN4_SHARE_DENY_BOTH).  If the OPEN fails, the client will
      fail the application's open request.
    </t>

    <t>
      Pseudo-code definition of the semantics:

      <figure>
        <artwork>
  if (request.access == 0)
          return (NFS4ERR_INVAL)
  else if ((request.access &amp; file_state.deny) ||
      (request.deny &amp; file_state.access))
          return (NFS4ERR_DENIED)
        </artwork>
      </figure>
    </t>

    <t>
      This checking of share reservations on OPEN is done with no
      exception for an existing OPEN for the same open-owner.
    </t>

    <t>
      The constants used for the OPEN and OPEN_DOWNGRADE operations
      for the access and deny fields are as follows:

<figure>
 <artwork>
const OPEN4_SHARE_ACCESS_READ   = 0x00000001;
const OPEN4_SHARE_ACCESS_WRITE  = 0x00000002;
const OPEN4_SHARE_ACCESS_BOTH   = 0x00000003;

const OPEN4_SHARE_DENY_NONE     = 0x00000000;
const OPEN4_SHARE_DENY_READ     = 0x00000001;
const OPEN4_SHARE_DENY_WRITE    = 0x00000002;
const OPEN4_SHARE_DENY_BOTH     = 0x00000003;
 </artwork>
</figure>
    </t>

  </section>
  <section title="OPEN/CLOSE Operations">

    <t>
      To provide correct share semantics, a client MUST use the OPEN
      operation to obtain the initial filehandle and indicate the
      desired access and what access, if any, to deny.  Even if the
      client intends to use one of the special stateids
      (anonymous stateid or READ bypass stateid), it must
      still obtain the filehandle for the regular file with the OPEN
      operation so the appropriate share semantics can be applied.
      Clients that do not have a deny mode built into their programming
      interfaces for opening a file should request a deny mode of
      OPEN4_SHARE_DENY_NONE.
    </t>

    <t>
      The OPEN operation with the CREATE flag also subsumes the CREATE
      operation for regular files as used in previous versions of the NFS
      protocol.  This allows a create with a share to be done atomically.
    </t>

    <t>
      The CLOSE operation removes all share reservations held by the
      open-owner on that file.  If byte-range locks are held, the client
      SHOULD release all locks before issuing a CLOSE.  The server MAY
      free all outstanding locks on CLOSE, but some servers may not
      support the CLOSE of a file that still has byte-range locks held.
      The server MUST return failure, NFS4ERR_LOCKS_HELD, if any locks
      would exist after the CLOSE.
    </t>

    <t>
      The LOOKUP operation will return a filehandle without establishing
      any lock state on the server.  Without a valid stateid, the server
      will assume that the client has the least access. For example, if
      one client opened a file with OPEN4_SHARE_DENY_BOTH and another
      client accesses the file via a filehandle obtained through LOOKUP,
      the second client could only read the file using the special READ
      bypass stateid.  The second client could not WRITE the file at all
      because it would not have a valid stateid from OPEN and the special
      anonymous stateid would not be allowed access.
    </t>

    <section title="Close and Retention of State Information">

      <t>
        Since a CLOSE operation requests deallocation of a stateid, dealing
        with retransmission of the CLOSE may pose special difficulties,
        since the state information, which normally would be used to
        determine the state of the open file being designated, might be
        deallocated, resulting in an NFS4ERR_BAD_STATEID error.
      </t>

      <t>
        Servers may deal with this problem in a number of ways.  To provide
        the greatest degree of assurance that the protocol is being used
        properly, a server should, rather than deallocate the stateid,
        mark it as close-pending, and retain the stateid with this status,
        until later deallocation.  In this way, a retransmitted CLOSE can
        be recognized since the stateid points to state information with
        this distinctive status, so that it can be handled without error.
      </t>

      <t>
        When adopting this strategy, a server should retain the state
        information until the earliest of:

        <list style='symbols'>
          <t>
            Another validly sequenced request for the same open-owner,
            that is not a retransmission.
          </t>

          <t>
            The time that an open-owner is freed by the server due to period
            with no activity.
          </t>

          <t>
            All locks for the client are freed as a result of a SETCLIENTID.
          </t>
        </list>
      </t>

      <t>
        Servers may avoid this complexity, at the cost of less complete
        protocol error checking, by simply responding NFS4_OK in the event
        of a CLOSE for a deallocated stateid, on the assumption that this
        case must be caused by a retransmitted close.  When adopting this
        approach, it is desirable to at least log an error when returning
        a no-error indication in this situation.  If the server maintains
        a reply-cache mechanism, it can verify that the CLOSE is indeed a
        retransmission and avoid error logging in most cases.
      </t>

    </section>
  </section>

  <section title="Open Upgrade and Downgrade">

    <t>
      When an OPEN is done for a file and the open-owner for which
      the open is being done already has the file open, the result
      is to upgrade the open file status maintained on the server to
      include the access and deny bits specified by the new OPEN as
      well as those for the existing OPEN.  The result is that there
      is one open file, as far as the protocol is concerned, and it
      includes the union of the access and deny bits for all of the OPEN
      requests completed.  Only a single CLOSE will be done to reset
      the effects of both OPENs.  Note that the client, when issuing
      the OPEN, may not know that the same file is in fact being opened.
      The above only applies if both OPENs result in the OPENed object
      being designated by the same filehandle.
    </t>

    <t>
      When the server chooses to export multiple filehandles
      corresponding to the same file object and returns different
      filehandles on two different OPENs of the same file object,
      the server MUST NOT "OR" together the access and deny bits and
      coalesce the two open files.  Instead, the server must maintain
      separate OPENs with separate stateids and will require separate
      CLOSEs to free them.
    </t>

    <t>
      When multiple open files on the client are merged into a single
      open file object on the server, the close of one of the open files
      (on the client) may necessitate change of the access and deny
      status of the open file on the server.  This is because the union
      of the access and deny bits for the remaining opens may be smaller
      (i.e., a proper subset) than previously.  The OPEN_DOWNGRADE
      operation is used to make the necessary change, and the client
      should use it to update the server so that share reservation
      requests by other clients are handled properly. The stateid
      returned has the same "other" field as that passed to the server.
      The seqid value in the returned stateid MUST be incremented (<xref target='ss:fl:stateids' />),
      even in situations in which there has been no change to the access and
      deny bits for the file.
    </t>

  </section>
  <section title="Short and Long Leases">

    <t>
      When determining the time period for the server lease, the
      usual lease trade-offs apply.  Short leases are good for fast
      server recovery at a cost of increased RENEW or READ (with
      zero length) requests.  Longer leases are certainly kinder and
      gentler to servers trying to handle very large numbers of clients.
      The number of RENEW requests drops in proportion to the lease time.
      The disadvantages of long leases are slower recovery after server
      failure (the server must wait for the leases to expire and the
      grace period to elapse before granting new lock requests) and
      increased file contention (if the client fails to transmit an unlock
      request, then the server must wait for lease expiration before
      granting new locks).
    </t>

    <t>
      Long leases are usable if the server is able to store lease state
      in non-volatile memory.  Upon recovery, the server can reconstruct
      the lease state from its non-volatile memory and continue operation
      with its clients, and therefore long leases would not be an issue.
    </t>

  </section>
  <section title="Clocks, Propagation Delay, and Calculating Lease Expiration">

    <t>
      To avoid the need for synchronized clocks, lease times are granted
      by the server as a time delta.  However, there is a requirement
      that the client and server clocks do not drift excessively over
      the duration of the lock.  There is also the issue of propagation
      delay across the network -- which could easily be several hundred
      milliseconds -- as well as the possibility that requests will be
      lost and need to be retransmitted.
    </t>

    <t>
      To take propagation delay into account, the client should subtract
      it from lease times (e.g., if the client estimates the one-way
      propagation delay as 200 msec, then it can assume that the lease
      is already 200 msec old when it gets it).  In addition, it will
      take another 200 msec to get a response back to the server.
      So the client must send a lock renewal or write data back to the
      server 400 msec before the lease would expire.
    </t>

    <t>
      The server's lease period configuration should take into account
      the network distance of the clients that will be accessing the
      server's resources.  It is expected that the lease period will
      take into account the network propagation delays and other network
      delay factors for the client population.  Since the protocol does
      not allow for an automatic method to determine an appropriate
      lease period, the server's administrator may have to tune the
      lease period.
    </t>

  </section>
  <section anchor="sec:mig_state" title="Migration, Replication, and State">

    <t>
      When responsibility for handling a given file system is transferred
      to a new server (migration) or the client chooses to use an
      alternative server (e.g., in response to server unresponsiveness) in
      the context of file system replication, the appropriate handling of
      state shared between the client and server (i.e., locks, leases,
      stateids, and client IDs) is as described below.  The handling
      differs between migration and replication.  For a related discussion
      of file server state and recovery of same, see the subsections of
      <xref target="ss:fl:crash_recov" />.
    </t>

    <t>
      In cases in which one server is expected to accept opaque values
      from the client that originated from another server, the
      servers SHOULD encode the opaque values in big-endian byte
      order.  If this is done, the new server will be able to 
      parse values like stateids, directory cookies, filehandles,
      etc. even if their native byte order is different from that of
      other servers cooperating in the replication and migration of the
      file system.
    </t>

    <section title="Migration and State">

      <t>
        In the case of migration, the servers involved in the migration
        of a file system SHOULD transfer all server state from the
        original server to the new server.  This must be done in a way that
        is transparent to the client.  This state transfer will ease the
        client's transition when a file system migration occurs.  If the
        servers are successful in transferring all state, the client
        will continue to use stateids assigned by the original server.
        Therefore, the new server must recognize these stateids as valid.
        This holds true for the client ID as well.  Since responsibility
        for an entire file system is transferred with a migration event,
        there is no possibility that conflicts will arise on the new
        server as a result of the transfer of locks.
      </t>

      <t>
        As part of the transfer of information between servers, leases
        would be transferred as well.  The leases being transferred to
        the new server will typically have a different expiration time
        from those for the same client, previously on the old server.
        To maintain the property that all leases on a given server for a
        given client expire at the same time, the server should advance
        the expiration time to the later of the leases being transferred
        or the leases already present.  This allows the client to maintain
        lease renewal of both classes without special effort.
      </t>

      <t>
        The servers may choose not to transfer the state information
        upon migration.  However, this choice is discouraged.  In this
        case, when the client presents state information from the
        original server (e.g., in a RENEW operation or a READ operation
        of zero length), the client must be prepared to receive either
        NFS4ERR_STALE_CLIENTID or NFS4ERR_STALE_STATEID from the new
        server.  The client should then recover its state information as
        it normally would in response to a server failure.  The new server
        must take care to allow for the recovery of state information as
        it would in the event of server restart.
      </t>

      <t>
        A client SHOULD re-establish new callback information
        with the new server as soon as possible, according to
        sequences described in
        Sections <xref target="OP_SETCLIENTID" format="counter"/>
        and <xref target="OP_SETCLIENTID_CONFIRM" format="counter"/>.
        This ensures that server operations are not blocked by
        the inability to recall delegations.
      </t>

    </section>
    <section title="Replication and State">

      <t>
        Since client switch-over in the case of replication is not
        under server control, the handling of state is different.
        In this case, leases, stateids, and client IDs do not have validity
        across a transition from one server to another.  The client must
        re-establish its locks on the new server.  This can be compared
        to the re&nbhy;establishment of locks by means of reclaim-type
        requests after a server reboot.  The difference is that the
        server has no provision to distinguish requests reclaiming locks
        from those obtaining new locks or to defer the latter.  Thus,
        a client re&nbhy;establishing a lock on the new server (by means of
        a LOCK or OPEN request), may have the requests denied due to a
        conflicting lock.  Since replication is intended for read-only
        use of file systems, such denial of locks should not pose large
        difficulties in practice.  When an attempt to re&nbhy;establish a lock
        on a new server is denied, the client should treat the situation
        as if its original lock had been revoked.
      </t>

    </section>
    <section title="Notification of Migrated Lease">

      <t>
        In the case of lease renewal, the client may not be submitting
        requests for a file system that has been migrated to another server.
        This can occur because of the implicit lease renewal mechanism.
        The client renews leases for all file systems when submitting a
        request to any one file system at the server.
      </t>

      <t>
        In order for the client to schedule renewal of leases that may
        have been relocated to the new server, the client must find out
        about lease relocation before those leases expire.  To accomplish
        this, all operations that implicitly renew leases for a client
        (such as OPEN, CLOSE, READ, WRITE, RENEW, LOCK, and others)
        will return the error NFS4ERR_LEASE_MOVED if responsibility for
        any of the leases to be renewed has been transferred to a new
        server.  This condition will continue until the client receives
        an NFS4ERR_MOVED error and the server receives the subsequent
        GETATTR(fs_locations) for an access to each file system for which
        a lease has been moved to a new server. By convention, the compound
        including the GETATTR(fs_locations) SHOULD append a RENEW operation
        to permit the server to identify the client doing the access.
      </t>

      <t>
       Upon receiving the NFS4ERR_LEASE_MOVED error, a client that supports
       file system migration MUST probe all file systems from that server on
       which it holds open state. Once the client has successfully probed
       all those file systems that are migrated, the server MUST resume normal
       handling of stateful requests from that client.
      </t>

      <t>
       In order to support legacy clients that do not handle the
       NFS4ERR_LEASE_MOVED error correctly, the server SHOULD time out after a
       wait of at least two lease periods, at which time it will resume normal
       handling of stateful requests from all clients. If a client attempts to
       access the migrated files, the server MUST reply with NFS4ERR_MOVED.
      </t>

      <t>
        When the client receives an NFS4ERR_MOVED error,
        the client can follow the normal process to obtain the new server
        information (through the fs_locations attribute) and perform
        renewal of those leases on the new server.
        If the server has not had state transferred to it transparently,
        the client will receive either NFS4ERR_STALE_CLIENTID or NFS4ERR_STALE_STATEID
        from the new server, as described above. The client can then recover
        state information as it does in the event of server failure.
      </t>

    </section>
    <section title="Migration and the lease_time Attribute">

      <t>
        In order that the client may appropriately manage its leases
        in the case of migration, the destination server must establish
        proper values for the lease_time attribute.
      </t>

      <t>
        When state is transferred transparently, that state should include
        the correct value of the lease_time attribute.  The lease_time
        attribute on the destination server must never be less than that
        on the source since this would result in premature expiration of
        leases granted by the source server.  Upon migration, in which state
        is transferred transparently, the client is under no obligation
        to refetch the lease_time attribute and may continue to use
        the value previously fetched (on the source server).
      </t>

      <t>
        If state has not been transferred transparently (i.e., the client
        sees a real or simulated server reboot), the client should fetch
        the value of lease_time on the new (i.e., destination) server
        and use it for subsequent locking requests.  However, the server
        must respect a grace period at least as long as the lease_time on
        the source server, in order to ensure that clients have ample
        time to reclaim their locks before potentially conflicting
        non-reclaimed locks are granted.  The means by which the new
        server obtains the value of lease_time on the old server is left
        to the server implementations.  It is not specified by the
        NFSv4 protocol.
      </t>
    </section>
  </section>
</section>

<section anchor="sec:client_caching" title="Client-Side Caching">

  <t>
    Client-side caching of data, file attributes, and filenames is
    essential to providing good performance with the NFS protocol.
    Providing distributed cache coherence is a difficult problem,
    and previous versions of the NFS protocol have not attempted it.
    Instead, several NFS client implementation techniques have been used
    to reduce the problems that a lack of coherence poses for users.
    These techniques have not been clearly defined by earlier protocol
    specifications, and it is often unclear what is valid or invalid
    client behavior.
  </t>

  <t>
    The NFSv4 protocol uses many techniques similar to those
    that have been used in previous protocol versions.  The NFSv4
    protocol does not provide distributed cache coherence.  However,
    it defines a more limited set of caching guarantees to allow locks
    and share reservations to be used without destructive interference
    from client-side caching.
  </t>

  <t>
    In addition, the NFSv4 protocol introduces a delegation
    mechanism that allows many decisions normally made by the server
    to be made locally by clients.  This mechanism provides efficient
    support of the common cases where sharing is infrequent or where
    sharing is read-only.
  </t>

  <section title="Performance Challenges for Client-Side Caching">

    <t>
      Caching techniques used in previous versions of the NFS protocol have
      been successful in providing good performance.  However, several
      scalability challenges can arise when those techniques are used
      with very large numbers of clients.  This is particularly true when
      clients are geographically distributed, which classically increases
      the latency for cache revalidation requests.
    </t>

    <t>
      The previous versions of the NFS protocol repeat their file data
      cache validation requests at the time the file is opened.  This
      behavior can have serious performance drawbacks.  A common case is
      one in which a file is only accessed by a single client.  Therefore,
      sharing is infrequent.
    </t>

    <t>
      In this case, repeated reference to the server to find that no
      conflicts exist is expensive.  A better option with regards to
      performance is to allow a client that repeatedly opens a file to do
      so without reference to the server.  This is done until potentially
      conflicting operations from another client actually occur.
    </t>

    <t>
      A similar situation arises in connection with file locking.  Sending
      file lock and unlock requests to the server as well as the READ and
      WRITE requests necessary to make data caching consistent with the
      locking semantics (see <xref target="ss:cc:dcfl" />)
      can severely limit performance.  When locking
      is used to provide protection against infrequent conflicts, a large
      penalty is incurred.  This penalty may discourage the use of file
      locking by applications.
    </t>

    <t>
      The NFSv4 protocol provides more aggressive caching
      strategies with the following design goals:

      <list style='symbols'>
        <t>
          Compatibility with a large range of server semantics.
        </t>

        <t>
          Providing the same caching benefits as previous versions of the
          NFS protocol when unable to provide the more aggressive model.
        </t>

        <t>
          Organizing requirements for aggressive caching so that a large
          portion of the benefit can be obtained even when not all of the
          requirements can be met.
        </t>
      </list>
    </t>

    <t>
      The appropriate requirements for the server are discussed in later
      sections, in which specific forms of caching are covered (see 
      <xref target="ss:cc:open_dele" />).
    </t>

  </section>
  <section title="Delegation and Callbacks">

    <t>
      Recallable delegation of server responsibilities for a file to a
      client improves performance by avoiding repeated requests to the
      server in the absence of inter-client conflict.  With the use of a
      "callback" RPC from server to client, a server recalls delegated
      responsibilities when another client engages in the sharing of a
      delegated file.
    </t>

    <t>
      A delegation is passed from the server to the client, specifying the
      object of the delegation and the type of delegation.  There are
      different types of delegations, but each type contains a stateid to be
      used to represent the delegation when performing operations that
      depend on the delegation.  This stateid is similar to those
      associated with locks and share reservations but differs in that the
      stateid for a delegation is associated with a client ID and may be used
      on behalf of all the open-owners for the given client.  A delegation
      is made to the client as a whole and not to any specific process or
      thread of control within it.
    </t>

    <t>
      Because callback RPCs may not work in all environments (due to
      firewalls, for example), correct protocol operation does not depend
      on them.  Preliminary testing of callback functionality by means of
      a CB_NULL procedure determines whether callbacks can be supported.
      The CB_NULL procedure checks the continuity of the callback path.
      A server makes a preliminary assessment of callback availability to
      a given client and avoids delegating responsibilities until it has
      determined that callbacks are supported.  Because the granting of
      a delegation is always conditional upon the absence of conflicting
      access, clients must not assume that a delegation will be granted,
      and they must always be prepared for OPENs to be processed without
      any delegations being granted.
    </t>

    <t>
      Once granted, a delegation behaves in most ways like a lock.  There
      is an associated lease that is subject to renewal, together with all
      of the other leases held by that client.
    </t>

    <t>
      Unlike locks, an operation by a second client to a delegated file
      will cause the server to recall a delegation through a callback.
    </t>

    <t>
      On recall, the client holding the delegation must flush modified
      state (such as modified data) to the server and return the
      delegation.  The conflicting request will not be acted on until
      the recall is complete.  The recall is considered complete when
      the client returns the delegation or the server times out its wait
      for the delegation to be returned and revokes the delegation as
      a result of the timeout.  In the interim, the server will either
      delay responding to conflicting requests or respond to them with
      NFS4ERR_DELAY.  Following the resolution of the recall, the
      server has the information necessary to grant or deny the second
      client's request.
    </t>

    <t>
      At the time the client receives a delegation recall, it may have
      substantial state that needs to be flushed to the server.  Therefore,
      the server should allow sufficient time for the delegation to be
      returned since it may involve numerous RPCs to the server.  If the
      server is able to determine that the client is diligently flushing
      state to the server as a result of the recall, the server MAY extend
      the usual time allowed for a recall.  However, the time allowed for
      recall completion should not be unbounded.
    </t>

    <t>
      An example of this is when responsibility to mediate opens on a given
      file is delegated to a client (see <xref target="ss:cc:open_dele" />).
      The server will not know what opens are in effect on the client.
      Without this knowledge, the server will be unable to determine if
      the access and deny state for the file allows any particular open
      until the delegation for the file has been returned.
    </t>

    <t>
      A client failure or a network partition can result in failure to
      respond to a recall callback.  In this case, the server will revoke
      the delegation; this in turn will render useless any modified state
      still on the client.
    </t>

    <t>
      Clients need to be aware that server implementers may enforce practical
      limitations on the number of delegations issued. Further, as there is
      no way to determine which delegations to revoke, the server is allowed
      to revoke any. If the server is implemented to revoke another delegation
      held by that client, then the client may be able to determine that 
      a limit has been reached because each new delegation request results
      in a revoke. The client could then determine which delegations it may not
      need and preemptively release them.
    </t>

    <section anchor="ss:cc:deleg_recovery" title="Delegation Recovery">

      <t>
        There are three situations that delegation recovery must deal with:

        <list style='symbols'>
          <t>
            Client reboot or restart
          </t>

          <t>
            Server reboot or restart (see <xref target='ss:fl:cl' />)
          </t>

          <t>
            Network partition (full or callback-only)
          </t>
        </list>
      </t>

      <t>
        In the event that the client reboots or restarts, the confirmation of
        a SETCLIENTID done with an nfs_client_id4 with a new verifier4 value
        will result in the release of byte-range locks and share reservations.
        Delegations, however, may be treated a bit differently.
      </t>

      <t>
        There will be situations in which delegations will need to be
        re&nbhy;established after a client reboots or restarts.  The reason for
        this is the client may have file data stored locally and this data
        was associated with the previously held delegations.  The client will
        need to re&nbhy;establish the appropriate file state on the server.
      </t>

      <t>
        To allow for this type of client recovery, the server MAY allow
        delegations to be retained after other sorts of locks are released.
        This implies that requests from other clients that conflict with these
        delegations will need to wait.  Because the normal recall process may
        require significant time for the client to flush changed state to the
        server, other clients need to be prepared for delays that occur because
        of a conflicting delegation.  In order to give clients a chance to get
        through the reboot process -- during which leases will not be
        renewed -- the server MAY extend the period for delegation
        recovery beyond the typical lease expiration period.  For open
        delegations, such delegations that are not released are reclaimed
        using OPEN with a claim type of CLAIM_DELEGATE_PREV.  (See
        Sections <xref target="ss:cc:cache_revoke" format="counter" />
        and <xref target="OP_OPEN" format="counter" /> for discussions
        of open delegation and the details of OPEN, respectively.)
      </t>

      <t>
        A server MAY support a claim type of CLAIM_DELEGATE_PREV, but if it
        does, it MUST NOT remove delegations upon SETCLIENTID_CONFIRM and
        instead MUST make them available for client reclaim using
        CLAIM_DELEGATE_PREV.  The server MUST NOT remove the delegations until
        either the client does a DELEGPURGE or one lease period has
        elapsed from the time -- whichever is later -- of the
        SETCLIENTID_CONFIRM or the last successful CLAIM_DELEGATE_PREV
        reclaim.
      </t>

      <t>
        Note that the requirement stated above is not meant to imply that,
        when the server is no longer obliged, as required above, to retain
        delegation information, it should necessarily dispose of it.
        Some specific cases are:
      </t>

      <t>
        <list style='symbols'>
          <t>
            When the period is terminated by the occurrence of DELEGPURGE,
            deletion of unreclaimed delegations is appropriate and desirable.
          </t>

          <t>
            When the period is terminated by a lease period elapsing without
            a successful CLAIM_DELEGATE_PREV reclaim, and that situation
            appears to be the result of a network partition (i.e., lease
            expiration has occurred), a server's lease expiration approach,
            possibly including the use of courtesy locks, would normally
            provide for the retention of unreclaimed delegations.  Even in
            the event that lease cancellation occurs, such delegation should
            be reclaimed using CLAIM_DELEGATE_PREV as part of network partition
            recovery.
          </t>

          <t>
            When the period of non-communicating is followed by a client
            reboot, unreclaimed delegations should also be reclaimable by
            use of CLAIM_DELEGATE_PREV as part of client reboot recovery.
          </t>

          <t>
            When the period is terminated by a lease period elapsing without
            a successful CLAIM_DELEGATE_PREV reclaim, and lease renewal
            is occurring, the server may well conclude that unreclaimed
            delegations have been abandoned and consider the situation as
            one in which an implied DELEGPURGE should be assumed.
          </t>
        </list>
      </t>

      <t>
        A server that supports a claim type of CLAIM_DELEGATE_PREV MUST support
        the DELEGPURGE operation, and similarly, a server that supports
        DELEGPURGE MUST support CLAIM_DELEGATE_PREV.  A server that does
        not support CLAIM_DELEGATE_PREV MUST return NFS4ERR_NOTSUPP if the
        client attempts to use that feature or performs a DELEGPURGE operation.
      </t>

      <t>
        Support for a claim type of CLAIM_DELEGATE_PREV is often referred to
        as providing for "client-persistent delegations" in that they allow
        the use of persistent storage on the client to store data written
        by the client, even across a client restart.  It should be noted
        that, with the optional exception noted below, this feature
        requires persistent storage to be used on the client and does not
        add to persistent storage requirements on the server.
      </t>

      <t>
        One good way to think about client-persistent delegations is that for
        the most part, they function like "courtesy locks", with special
        semantic adjustments to allow them to be retained across a client restart,
        which cause all other sorts of locks to be freed.  Such locks are generally
        not retained across a server restart.  The one exception is the
        case of simultaneous failure of the client and server and is discussed
        below.
      </t>

      <t>
        When the server indicates support of CLAIM_DELEGATE_PREV (implicitly)
        by returning NFS_OK to DELEGPURGE, a client with a write delegation
        can use write-back caching for data to be written to the server, deferring
        the write-back until such time as the delegation is recalled, possibly
        after intervening client restarts.  Similarly, when the server indicates
        support of CLAIM_DELEGATE_PREV, a client with a read delegation and
        an open-for-write subordinate to that delegation may be sure of the
        integrity of its persistently cached copy of the file after a client
        restart without specific verification of the change attribute.
      </t>

      <t>
        When the server reboots or restarts, delegations are reclaimed (using
        the OPEN operation with CLAIM_PREVIOUS) in a similar fashion to byte-range
        locks and share reservations.  However, there is a slight
        semantic difference.  In the normal case, if the server decides that a
        delegation should not be granted, it performs the requested action
        (e.g., OPEN) without granting any delegation.  For reclaim, the
        server grants the delegation, but a special designation is applied so
        that the client treats the delegation as having been granted but
        recalled by the server.  Because of this, the client has the duty to
        write all modified state to the server and then return the
        delegation.  This process of handling delegation reclaim reconciles
        three principles of the NFSv4 protocol:
      </t>

      <t>
        <list style='symbols'>
          <t>
            Upon reclaim, a client claiming resources assigned to it by an
            earlier server instance must be granted those resources.
          </t>

          <t>
            The server has unquestionable authority to determine whether
            delegations are to be granted and, once granted, whether they are
            to be continued.
          </t>

          <t>
            The use of callbacks is not to be depended upon until the client
            has proven its ability to receive them.
          </t>
        </list>
      </t>

      <t>
        When a client has more than a single open associated with a
        delegation, state for those additional opens can be established using
        OPEN operations of type CLAIM_DELEGATE_CUR.  When these are used to
        establish opens associated with reclaimed delegations, the server
        MUST allow them when made within the grace period.
      </t>

      <t>
        Situations in which there is a series of client and server restarts where
        there is no restart of both at the same time are dealt with via a
        combination of CLAIM_DELEGATE_PREV and CLAIM_PREVIOUS reclaim cycles.
        Persistent storage is needed only on the client.  For each server
        failure, a CLAIM_PREVIOUS reclaim cycle is done, while for each client
        restart, a CLAIM_DELEGATE_PREV reclaim cycle is done.
      </t>

      <t>
        To deal with the possibility of simultaneous failure of client and
        server (e.g., a data center power outage), the server MAY
        persistently store delegation information so that it can respond to
        a CLAIM_DELEGATE_PREV reclaim request that it receives from a
        restarting client.   This is the one case in which persistent
        delegation state can be retained across a server restart.  A server
        is not required to store this information, but if it does do so, it
        should do so for write delegations and for read delegations, during
        the pendency of which (across multiple client and/or server
        instances), some open-for-write was done as part of delegation.  When
        the space to persistently record such information is limited, the
        server should recall delegations in this class in preference to
        keeping them active without persistent storage recording.
      </t>

      <t>
        When a network partition occurs, delegations are subject to freeing
        by the server when the lease renewal period expires.  This is similar
        to the behavior for locks and share reservations, and as for locks
        and share reservations, it may be modified by support for "courtesy
        locks" in which locks are not freed in the absence of a conflicting
        lock request.  Whereas for locks and share reservations the freeing of
        locks will occur immediately upon the appearance of a conflicting
        request, for delegations, the server MAY institute a period during
        which conflicting requests are held off.  Eventually, the occurrence
        of a conflicting request from another client will cause revocation
        of the delegation.
      </t>

      <t>
        A loss of the callback path (e.g., by a later network configuration
        change) will have a similar effect in that it can also result in
        revocation of a delegation. A recall request will fail, and revocation
        of the delegation will result.
      </t>

      <t>
        A client normally finds out about revocation of a delegation when it
        uses a stateid associated with a delegation and receives one of the
        errors NFS4ERR_EXPIRED, NFS4ERR_BAD_STATEID, or NFS4ERR_ADMIN_REVOKED
        (NFS4ERR_EXPIRED indicates that all lock state associated with the
        client has been lost).  It also may find out about delegation revocation
        after a client reboot when it attempts to reclaim a delegation and
        receives NFS4ERR_EXPIRED.  Note that in the case of a revoked
        OPEN_DELEGATE_WRITE delegation, there are issues because data may
        have been modified by the client whose delegation is revoked and,
        separately, by other clients.  See <xref target="ss:cc:rrwod" /> for
        a discussion of such issues.  Note also that when delegations are
        revoked, information about the revoked delegation will be written
        by the server to stable storage (as described
        in <xref target="ss:fl:crash_recov" />).  This is done
        to deal with the case in which a server reboots after revoking a
        delegation but before the client holding the revoked delegation is
        notified about the revocation.
      </t>

      <t>
        Note that when there is a loss of a delegation, due to a network
        partition in which all locks associated with the lease are lost,
        the client will also receive the error NFS4ERR_EXPIRED.  This case
        can be distinguished from other situations in which delegations
        are revoked by seeing that the associated clientid becomes invalid
        so that NFS4ERR_STALE_CLIENTID is returned when it is used.
      </t>

      <t>
        When NFS4ERR_EXPIRED is returned, the server MAY retain information
        about the delegations held by the client, deleting those that are
        invalidated by a conflicting request.  Retaining such information
        will allow the client to recover all non-invalidated delegations
        using the claim type CLAIM_DELEGATE_PREV, once the
        SETCLIENTID_CONFIRM is done to recover.  Attempted recovery of
        a delegation that the client has no record of, typically because they
        were invalidated by conflicting requests, will result in the error
        NFS4ERR_BAD_RECLAIM.  Once a reclaim is attempted for all delegations
        that the client held, it SHOULD do a DELEGPURGE to allow any remaining
        server delegation information to be freed.
      </t>
    </section>
  </section>

  <section title="Data Caching">
    <t>
      When applications share access to a set of files, they need to be
      implemented so as to take account of the possibility of conflicting
      access by another application.  This is true whether the applications
      in question execute on different clients or reside on the same
      client.
    </t>

    <t>
      Share reservations and byte-range locks are the facilities the
      NFSv4 protocol provides to allow applications to coordinate
      access by providing mutual exclusion facilities.  The NFSv4
      protocol's data caching must be implemented such that it does
      not invalidate the assumptions that those using these facilities
      depend upon.
    </t>

    <section title="Data Caching and OPENs">
      <t>
        In order to avoid invalidating the sharing assumptions that
        applications rely on, NFSv4 clients should not provide cached
        data to applications or modify it on behalf of an application when
        it would not be valid to obtain or modify that same data via a READ
        or WRITE operation.
      </t>

      <t>
        Furthermore, in the absence of open delegation (see <xref
        target="ss:cc:open_dele" />), two additional rules apply.  Note
        that these rules are obeyed in practice by many NFSv2 and
        NFSv3 clients.

        <list style='symbols'>
          <t>
            First, cached data present on a client must be revalidated after
            doing an OPEN.  Revalidating means that the client fetches the
            change attribute from the server, compares it with the cached
            change attribute, and, if different, declares the cached data (as
            well as the cached attributes) as invalid.  This is to ensure
            that the data for the OPENed file is still correctly reflected
            in the client's cache.  This validation must be done at least
            when the client's OPEN operation includes DENY=WRITE or BOTH,
            thus terminating a period in which other clients may have had
            the opportunity to open the file with WRITE access.  Clients may
            choose to do the revalidation more often (such as at OPENs specifying
            DENY=NONE) to parallel the NFSv3 protocol's practice for
            the benefit of users assuming this degree of cache revalidation.
            <vspace blankLines='1' />
            Since the change attribute is updated for data and metadata
            modifications, some client implementers may be tempted to use the
            time_modify attribute and not the change attribute to validate cached data, so
            that metadata changes do not spuriously invalidate clean data.
            The implementer is cautioned against this approach.  The change
            attribute is guaranteed to change for each update to the file,
            whereas time_modify is guaranteed to change only at the granularity
            of the time_delta attribute.  Use by the client's data cache
            validation logic of time_modify and not the change attribute runs the risk of
            the client incorrectly marking stale data as valid.
          </t>

          <t>
            Second, modified data must be flushed to the server before closing
            a file OPENed for write.  This is complementary to the first rule.
            If the data is not flushed at CLOSE, the revalidation done after
            the client OPENs a file is unable to achieve its purpose.  The other
            aspect to flushing the data before close is that the data must
            be committed to stable storage, at the server, before the CLOSE
            operation is requested by the client.  In the case of a server
            reboot or restart and a CLOSEd file, it may not be possible
            to retransmit the data to be written to the file -- hence, this
            requirement.
          </t>
        </list>
      </t>
    </section>

    <section anchor="ss:cc:dcfl" title="Data Caching and File Locking">
      <t>
        For those applications that choose to use file locking instead of
        share reservations to exclude inconsistent file access, there is an
        analogous set of constraints that apply to client-side data caching.
        These rules are effective only if the file locking is used in a way
        that matches in an equivalent way the actual READ and WRITE
        operations executed.  This is as opposed to file locking that is
        based on pure convention.  For example, it is possible to manipulate
        a two-megabyte file by dividing the file into two one-megabyte
        regions and protecting access to the two regions by file locks on
        bytes zero and one.  A lock for write on byte zero of the file would
        represent the right to do READ and WRITE operations on the first
        region.  A lock for write on byte one of the file would represent the
        right to do READ and WRITE operations on the second region.  As long
        as all applications manipulating the file obey this convention, they
        will work on a local file system.  However, they may not work with
        the NFSv4 protocol unless clients refrain from data caching.
      </t>

      <t>
        The rules for data caching in the file locking environment are:

        <list style='symbols'>
          <t>
            First, when a client obtains a file lock for a particular region,
            the data cache corresponding to that region (if any cached data
            exists) must be revalidated.  If the change attribute indicates
            that the file may have been updated since the cached data was
            obtained, the client must flush or invalidate the cached data for
            the newly locked region.  A client might choose to invalidate all
            of the non-modified cached data that it has for the file,
            but the only requirement for correct operation is to invalidate
            all of the data in the newly locked region.
          </t>

          <t>
            Second, before releasing a write lock for a region, all modified
            data for that region must be flushed to the server.  The modified
            data must also be written to stable storage.
          </t>
        </list>
      </t>

      <t>
        Note that flushing data to the server and the invalidation of
        cached data must reflect the actual byte ranges locked or unlocked.
        Rounding these up or down to reflect client cache block boundaries
        will cause problems if not carefully done.  For example, writing a
        modified block when only half of that block is within an area being
        unlocked may cause invalid modification to the region outside the
        unlocked area.  This, in turn, may be part of a region locked by
        another client.  Clients can avoid this situation by synchronously
        performing portions of WRITE operations that overlap that portion
        (initial or final) that is not a full block.  Similarly, invalidating
        a locked area that is not an integral number of full buffer blocks
        would require the client to read one or two partial blocks from the
        server if the revalidation procedure shows that the data that the
        client possesses may not be valid.
      </t>

      <t>
        The data that is written to the server as a prerequisite to the
        unlocking of a region must be written, at the server, to stable
        storage.  The client may accomplish this either with synchronous
        writes or by following asynchronous writes with a COMMIT operation.
        This is required because retransmission of the modified data after
        a server reboot might conflict with a lock held by another client.
      </t>

      <t>
        A client implementation may choose to accommodate applications that
        use byte-range locking in non-standard ways (e.g., using a byte-range lock as
        a global semaphore) by flushing to the server more data upon a LOCKU
        than is covered by the locked range.  This may include modified data
        within files other than the one for which the unlocks are being done.
        In such cases, the client must not interfere with applications whose
        READs and WRITEs are being done only within the bounds of record
        locks that the application holds.  For example, an application locks
        a single byte of a file and proceeds to write that single byte.  A
        client that chose to handle a LOCKU by flushing all modified data to
        the server could validly write that single byte in response to an
        unrelated unlock.  However, it would not be valid to write the entire
        block in which that single written byte was located since it includes
        an area that is not locked and might be locked by another client.
        Client implementations can avoid this problem by dividing files
        with modified data into those for which all modifications are done
        to areas covered by an appropriate byte-range lock and those for which
        there are modifications not covered by a byte-range lock.  Any writes
        done for the former class of files must not include areas not locked
        and thus not modified on the client.
      </t>

    </section>
    <section title="Data Caching and Mandatory File Locking">

      <t>
        Client-side data caching needs to respect mandatory file locking when
        it is in effect.  The presence of mandatory file locking for a given
        file is indicated when the client gets back NFS4ERR_LOCKED from a
        READ or WRITE on a file it has an appropriate share reservation for.
        When mandatory locking is in effect for a file, the client must check
        for an appropriate file lock for data being read or written.  If a
        lock exists for the range being read or written, the client may
        satisfy the request using the client's validated cache.  If an
        appropriate file lock is not held for the range of the READ or WRITE,
        the READ or WRITE request must not be satisfied by the client's
        cache and the request must be sent to the server for processing.
        When a READ or WRITE request partially overlaps a locked region, the
        request should be subdivided into multiple pieces with each region
        (locked or not) treated appropriately.
      </t>

    </section>
    <section anchor="ss:cc:dcfi" title="Data Caching and File Identity">

      <t>
        When clients cache data, the file data needs to be organized
        according to the file system object to which the data belongs.  For
        NFSv3 clients, the typical practice has been to assume for
        the purpose of caching that distinct filehandles represent distinct
        file system objects.  The client then has the choice to organize and
        maintain the data cache on this basis.
      </t>

      <t>
        In the NFSv4 protocol, there is now the possibility of having
        significant deviations from a "one filehandle per object"
        model, because a filehandle may be constructed on the basis of the
        object's pathname.  Therefore, clients need a reliable method to
        determine if two filehandles designate the same file system object.
        If clients were simply to assume that all distinct filehandles
        denote distinct objects and proceed to do data caching on this basis,
        caching inconsistencies would arise between the distinct client-side
        objects that mapped to the same server-side object.
      </t>

      <t>
        By providing a method to differentiate filehandles, the NFSv4
        protocol alleviates a potential functional regression in comparison
        with the NFSv3 protocol.  Without this method, caching
        inconsistencies within the same client could occur, and this has not
        been present in previous versions of the NFS protocol.  Note that it
        is possible to have such inconsistencies with applications executing
        on multiple clients, but that is not the issue being addressed here.
      </t>

      <t>
        For the purposes of data caching, the following steps allow an NFSv4
        client to determine whether two distinct filehandles denote
        the same server-side object:

        <list style='symbols'>
          <t>
            If GETATTR directed to two filehandles returns different values of
            the fsid attribute, then the filehandles represent distinct
            objects.
          </t>

          <t>
            If GETATTR for any file with an fsid that matches the fsid of the
            two filehandles in question returns a unique_handles attribute
            with a value of TRUE, then the two objects are distinct.
          </t>

          <t>
            If GETATTR directed to the two filehandles does not return the
            fileid attribute for both of the handles, then it cannot be
            determined whether the two objects are the same.  Therefore,
            operations that depend on that knowledge (e.g., client-side data
            caching) cannot be done reliably. Note that if GETATTR does not
            return the fileid attribute for both filehandles, it will return
            it for neither of the filehandles, since the fsid for both
            filehandles is the same.
          </t>

          <t>
            If GETATTR directed to the two filehandles returns different
            values for the fileid attribute, then they are distinct objects.
          </t>

          <t>
            Otherwise, they are the same object.
          </t>
        </list>
      </t>

    </section>
  </section>
  <section anchor="ss:cc:open_dele" title="Open Delegation">

    <t>
      When a file is being OPENed, the server may delegate further handling
      of opens and closes for that file to the opening client.  Any such
      delegation is recallable, since the circumstances that allowed for
      the delegation are subject to change.  In particular, the server may
      receive a conflicting OPEN from another client; the server must recall
      the delegation before deciding whether the OPEN from the other client
      may be granted.  Making a delegation is up to the server, and clients
      should not assume that any particular OPEN either will or will not
      result in an open delegation.  The following is a typical set of
      conditions that servers might use in deciding whether OPEN should
      be delegated:

      <list style='symbols'>
        <t>
          The client must be able to respond to the server's callback
          requests.  The server will use the CB_NULL procedure for a test
          of callback ability.
        </t>

        <t>
          The client must have responded properly to previous recalls.
        </t>

        <t>
          There must be no current open conflicting with the requested
          delegation.
        </t>

        <t>
          There should be no current delegation that conflicts with the
          delegation being requested.
        </t>

        <t>
          The probability of future conflicting open requests should be low,
          based on the recent history of the file.
        </t>

        <t>
          The existence of any server-specific semantics of OPEN/CLOSE that
          would make the required handling incompatible with the prescribed
          handling that the delegated client would apply (see below).
        </t>
      </list>
    </t>

    <t>
      There are two types of open delegations: OPEN_DELEGATE_READ and
      OPEN_DELEGATE_WRITE.  An OPEN_DELEGATE_READ delegation allows a
      client to handle, on its own, requests to
      open a file for reading that do not deny read access to others. It MUST,
      however, continue to send all requests to open a file for writing to the
      server. Multiple OPEN_DELEGATE_READ delegations may be outstanding
      simultaneously and do not conflict.  An OPEN_DELEGATE_WRITE
      delegation allows the client to handle, on its own, all opens.  Only
      one OPEN_DELEGATE_WRITE delegation may exist for a given file at a
      given time, and it is inconsistent with any OPEN_DELEGATE_READ
      delegations.
    </t>

    <t>
      When a single client holds an OPEN_DELEGATE_READ delegation, it is
      assured that no other client may modify the contents or attributes
      of the file. If more than one client holds an OPEN_DELEGATE_READ
      delegation, then the contents and attributes of that file are not
      allowed to change. When a client has an OPEN_DELEGATE_WRITE delegation,
      it may modify the file data since no other client will be accessing
      the file's data.  The client holding an OPEN_DELEGATE_WRITE delegation
      may only affect file attributes that are intimately connected with
      the file data: size, time_modify, and change.
    </t>

    <t>
      When a client has an open delegation, it does not send OPENs or
      CLOSEs to the server but updates the appropriate status internally.
      For an OPEN_DELEGATE_READ delegation, opens that cannot be handled locally
      (opens for write or that deny read access) must be sent to the
      server.
    </t>

    <t>
      When an open delegation is made, the response to the OPEN contains an
      open delegation structure that specifies the following:

      <list style='symbols'>
        <t>
          the type of delegation (read or write)
        </t>

        <t>
          space limitation information to control flushing of data on close
          (OPEN_DELEGATE_WRITE delegation only;
          see <xref target="ss:cc:oddc" />)
        </t>

        <t>
          an nfsace4 specifying read and write permissions
        </t>

        <t>
          a stateid to represent the delegation for READ and WRITE
        </t>
      </list>
    </t>

    <t>
      The delegation stateid is separate and distinct from the stateid for
      the OPEN proper.  The standard stateid, unlike the delegation
      stateid, is associated with a particular open-owner and will continue
      to be valid after the delegation is recalled and the file remains
      open.
    </t>

    <t>
      When a request internal to the client is made to open a file and open
      delegation is in effect, it will be accepted or rejected solely on
      the basis of the following conditions.  Any requirement for other
      checks to be made by the delegate should result in open delegation
      being denied so that the checks can be made by the server itself.

      <list style='symbols'>
        <t>
          The access and deny bits for the request and the file, as described
          in <xref target="ss:fl:share_res" />.
        </t>

        <t>
          The read and write permissions, as determined below.
        </t>
      </list>
    </t>

    <t>
      The nfsace4 passed with delegation can be used to avoid frequent
      ACCESS calls.  The permission check should be as follows:

      <list style='symbols'>
        <t>
          If the nfsace4 indicates that the open may be done, then it should
          be granted without reference to the server.
        </t>

        <t>
          If the nfsace4 indicates that the open may not be done, then an
          ACCESS request must be sent to the server to obtain the definitive
          answer.
        </t>
      </list>
    </t>

    <t>
      The server may return an nfsace4 that is more restrictive than the
      actual ACL of the file.  This includes an nfsace4 that specifies
      denial of all access.  Note that some common practices, such as
      mapping the traditional user "root" to the user "nobody", may make
      it incorrect to return the actual ACL of the file in the delegation
      response.
    </t>

    <t>
      The use of delegation, together with various other forms of caching,
      creates the possibility that no server authentication will ever be
      performed for a given user since all of the user's requests might
      be satisfied locally.  Where the client is depending on the server
      for authentication, the client should be sure authentication occurs
      for each user by use of the ACCESS operation.  This should be the
      case even if an ACCESS operation would not be required otherwise.
      As mentioned before, the server may enforce frequent authentication
      by returning an nfsace4 denying all access with every open delegation.
    </t>

    <section anchor="ss:cc:oddc" title="Open Delegation and Data Caching">

      <t>
        OPEN delegation allows much of the message overhead associated with
        the opening and closing files to be eliminated.  An open when an open
        delegation is in effect does not require that a validation message be
        sent to the server unless there exists a potential for conflict with the
        requested share mode. The continued endurance of the "OPEN_DELEGATE_READ
        delegation" provides a guarantee that no OPEN for write and thus no
        write has occurred that did not originate from this client.
        Similarly, when closing a file opened for write
        and if OPEN_DELEGATE_WRITE delegation is in effect, the data written does
        not have to be flushed to the server until the open delegation is
        recalled.  The continued endurance of the open delegation provides
        a guarantee that no open and thus no read or write has been done by
        another client.
      </t>

      <t>
        For the purposes of open delegation, READs and WRITEs done
        without an OPEN (anonymous and READ bypass stateids) are
        treated as the functional equivalents of a corresponding
        type of OPEN.  READs and WRITEs done with an anonymous
        stateid done by another client will force the server to
        recall an OPEN_DELEGATE_WRITE delegation.  A WRITE with an
        anonymous stateid done by another client will force a recall
        of OPEN_DELEGATE_READ delegations.  The handling of a READ bypass
        stateid is identical, except that a READ done with a READ bypass
        stateid will not force a recall of an OPEN_DELEGATE_READ delegation.
      </t>

      <t>
        With delegations, a client is able to avoid writing data to the
        server when the CLOSE of a file is serviced.  The file close system
        call is the usual point at which the client is notified of a lack of
        stable storage for the modified file data generated by the
        application.  At the close, file data is written to the server, and
        through normal accounting the server is able to determine if the
        available file system space for the data has been exceeded (i.e.,
        the server returns NFS4ERR_NOSPC or NFS4ERR_DQUOT).  This accounting
        includes quotas.  The introduction of delegations requires that an
        alternative method be in place for the same type of communication
        to occur between client and server.
      </t>

      <t>
        In the delegation response, the server provides either the limit of
        the size of the file or the number of modified blocks and associated
        block size.  The server must ensure that the client will be able to
        flush to the server data of a size equal to that provided in the
        original delegation.  The server must make this assurance for all
        outstanding delegations.  Therefore, the server must be careful in
        its management of available space for new or modified data, taking
        into account available file system space and any applicable quotas.
        The server can recall delegations as a result of managing the
        available file system space.  The client should abide by the server's
        state space limits for delegations.  If the client exceeds the stated
        limits for the delegation, the server's behavior is undefined.
      </t>

      <t>
        Based on server conditions, quotas, or available file system space, the
        server may grant OPEN_DELEGATE_WRITE delegations with very
        restrictive space limitations.  The limitations may be defined
        in a way that will always force modified data to be flushed to the
        server on close.
      </t>

      <t>
        With respect to authentication, flushing modified data to the server
        after a CLOSE has occurred may be problematic.  For example, the user
        of the application may have logged off the client, and unexpired
        authentication credentials may not be present.  In this case, the
        client may need to take special care to ensure that local unexpired
        credentials will in fact be available.  One way that this may be
        accomplished is by tracking the expiration time of credentials and
        flushing data well in advance of their expiration.
      </t>

    </section>
    <section title="Open Delegation and File Locks">

      <t>
        When a client holds an OPEN_DELEGATE_WRITE delegation, lock operations may be
        performed locally.  This includes those required for mandatory file
        locking.  This can be done since the delegation implies that there can
        be no conflicting locks.  Similarly, all of the revalidations that
        would normally be associated with obtaining locks and the flushing
        of data associated with the releasing of locks need not be done.
      </t>

      <t>
        When a client holds an OPEN_DELEGATE_READ delegation, lock operations are not
        performed locally.  All lock operations, including those requesting
        non-exclusive locks, are sent to the server for resolution.
      </t>

    </section>
    <section anchor="ss:cc:handle_cb_getattr" title="Handling of CB_GETATTR">

      <t>
        The server needs to employ special handling for a GETATTR where the
        target is a file that has an OPEN_DELEGATE_WRITE delegation in effect.  The
        reason for this is that the client holding the OPEN_DELEGATE_WRITE delegation may
        have modified the data, and the server needs to reflect this change to
        the second client that submitted the GETATTR.  Therefore, the client
        holding the OPEN_DELEGATE_WRITE delegation needs to be interrogated.  The server
        will use the CB_GETATTR operation.  The only attributes that the
        server can reliably query via CB_GETATTR are size and change.
      </t>
      <t>
        Since CB_GETATTR is being used to satisfy another client's GETATTR
        request, the server only needs to know if the client holding the
        delegation has a modified version of the file.  If the client's copy
        of the delegated file is not modified (data or size), the server can
        satisfy the second client's GETATTR request from the attributes stored
        locally at the server.  If the file is modified, the server only needs
        to know about this modified state.  If the server determines that the
        file is currently modified, it will respond to the second client's
        GETATTR as if the file had been modified locally at the server.
      </t>
      <t>
        Since the form of the change attribute is determined by the server and
        is opaque to the client, the client and server need to agree on a
        method of communicating the modified state of the file.  For the size
        attribute, the client will report its current view of the file size.
        For the change attribute, the handling is more involved.
      </t>
      <t>
        For the client, the following steps will be taken when receiving an
        OPEN_DELEGATE_WRITE delegation:
        <list style="symbols">
          <t>
            The value of the change attribute will be obtained from the server and
            cached.  Let this value be represented by c.
          </t>
          <t>
            The client will create a value greater than c that will be used for
            communicating that modified data is held at the client.  Let
            this value be represented by d.
          </t>
          <t>
            When the client is queried via CB_GETATTR for the change attribute, it
            checks to see if it holds modified data.  If the file is modified, the
            value d is returned for the change attribute value.  If this file is
            not currently modified, the client returns the value c for the change
            attribute.
          </t>
        </list>
        For simplicity of implementation, the client MAY for each CB_GETATTR
        return the same value d.  This is true even if, between successive
        CB_GETATTR operations, the client again modifies in the file's data or
        metadata in its cache.  The client can return the same value because
        the only requirement is that the client be able to indicate to the
        server that the client holds modified data.  Therefore, the value of d
        may always be c + 1.
      </t>
      <t>
        While the change attribute is opaque to the client in the sense that
        it has no idea what units of time, if any, the server is counting
        change with, it is not opaque in that the client has to treat it as an
        unsigned integer, and the server has to be able to see the results of
        the client's changes to that integer.  Therefore, the server MUST
        encode the change attribute in network byte order when sending it
        to the client.  The client MUST decode it from network byte order
        to its native order when receiving it, and the client MUST encode
        it in network byte order when sending it to the server.  For
        this reason, the change attribute is defined as an unsigned integer
        rather than an opaque array of bytes.
      </t>
      <t>
        For the server, the following steps will be taken when providing an
        OPEN_DELEGATE_WRITE delegation:
        <list style="symbols">
          <t>
            Upon providing an OPEN_DELEGATE_WRITE delegation, the server will cache a copy of the
            change attribute in the data structure it uses to record the
            delegation.  Let this value be represented by sc.
          </t>
          <t>
            When a second client sends a GETATTR operation on the same file to the
            server, the server obtains the change attribute from the first client.
            Let this value be cc.
          </t>
          <t>
            If the value cc is equal to sc, the file is not modified and the
            server returns the current values for change, time_metadata, and
            time_modify (for example) to the second client.
          </t>
          <t>
            If the value cc is NOT equal to sc, the file is currently modified at
            the first client and most likely will be modified at the server at a
            future time.  The server then uses its current time to construct
            attribute values for time_metadata and time_modify.  A new value of
            sc, which we will call nsc, is computed by the server, such that nsc
            >= sc + 1.  The server then returns the constructed time_metadata,
            time_modify, and nsc values to the requester.  The server replaces sc
            in the delegation record with nsc.  To prevent the possibility of
            time_modify, time_metadata, and change from appearing to go backward
            (which would happen if the client holding the delegation fails to
            write its modified data to the server before the delegation is revoked
            or returned), the server SHOULD update the file's metadata record with
            the constructed attribute values.  For reasons of reasonable
            performance, committing the constructed attribute values to stable
            storage is OPTIONAL.
          </t>
        </list>
      </t>
      <t>
        As discussed earlier in this section, the client MAY return the same
        cc value on subsequent CB_GETATTR calls, even if the file was modified
        in the client's cache yet again between successive CB_GETATTR calls.
        Therefore, the server must assume that the file has been modified yet
        again and MUST take care to ensure that the new nsc it constructs and
        returns is greater than the previous nsc it returned.  An example
        implementation's delegation record would satisfy this mandate by
        including a boolean field (let us call it "modified") that is set to
        FALSE when the delegation is granted, and an sc value set at the time
        of grant to the change attribute value. The modified field would be
        set to TRUE the first time cc != sc and would stay TRUE until the
        delegation is returned or revoked.  The processing for constructing
        nsc, time_modify, and time_metadata would use this pseudo-code:
      </t>

        <figure>
          <artwork>
    if (!modified) {
        do CB_GETATTR for change and size;

        if (cc != sc)
            modified = TRUE;
    } else {
        do CB_GETATTR for size;
    }

    if (modified) {
        sc = sc + 1;
        time_modify = time_metadata = current_time;
        update sc, time_modify, time_metadata into file's metadata;
    }
      </artwork>
    </figure>

      <t>
        This would return to the client (that sent GETATTR) the
        attributes it requested but would make sure that size comes from
        what CB_GETATTR returned. The server would not update the file's
        metadata with the client's modified size.
      </t>
      <t>
        In the case that the file attribute size is different than the
        server's current value, the server treats this as a modification
        regardless of the value of the change attribute retrieved via
        CB_GETATTR and responds to the second client as in the last step.
      </t>
      <t>
        This methodology resolves issues of clock differences between client
        and server and other scenarios where the use of CB_GETATTR breaks down.
      </t>
      <t>
        It should be noted that the server is under no obligation to use
        CB_GETATTR; therefore, the server MAY simply recall the delegation
        to avoid its use.
      </t>
    </section>
    <section title="Recall of Open Delegation">

      <t>
        The following events necessitate the recall of an open delegation:

        <list style='symbols'>
          <t>
            Potentially conflicting OPEN request (or READ/WRITE done with
            "special" stateid)
          </t>

          <t>
            SETATTR issued by another client
          </t>

          <t>
            REMOVE request for the file
          </t>

          <t>
            RENAME request for the file as either source or target of the
            RENAME
          </t>
        </list>
      </t>

      <t>
        Whether a RENAME of a directory in the path leading to the file
        results in the recall of an open delegation depends on the semantics of
        the server file system.  If that file system denies such RENAMEs when
        a file is open, the recall must be performed to determine whether
        the file in question is, in fact, open.
      </t>

      <t>
        In addition to the situations above, the server may choose to
        recall open delegations at any time if resource constraints make
        it advisable to do so.  Clients should always be prepared for the
        possibility of a recall.
      </t>

      <t>
        When a client receives a recall for an open delegation, it needs
        to update state on the server before returning the delegation.
        These same updates must be done whenever a client chooses to return
        a delegation voluntarily.  The following items of state need to be
        dealt with:

        <list style='symbols'>
          <t>
            If the file associated with the delegation is no longer open and
            no previous CLOSE operation has been sent to the server, a CLOSE
            operation must be sent to the server.
          </t>

          <t>
            If a file has other open references at the client, then OPEN
            operations must be sent to the server.  The appropriate stateids
            will be provided by the server for subsequent use by the client
            since the delegation stateid will not longer be valid.  These OPEN
            requests are done with the claim type of CLAIM_DELEGATE_CUR.  This
            will allow the presentation of the delegation stateid so that the
            client can establish the appropriate rights to perform the OPEN.
            (See <xref target="OP_OPEN" /> for details.)
          </t>

          <t>
            If there are granted file locks, the corresponding LOCK operations
            need to be performed.  This applies to the OPEN_DELEGATE_WRITE delegation
            case only.
          </t>

          <t>
            For an OPEN_DELEGATE_WRITE delegation, if at the time of
            the recall the file is not open for write, all modified
            data for the file must be flushed to the server.  If the
            delegation had not existed, the client would have done
            this data flush before the CLOSE operation.
          </t>

          <t>
            For an OPEN_DELEGATE_WRITE delegation, when a file is
            still open at the time of the recall, any modified data
            for the file needs to be flushed to the server.
          </t>

          <t>
            With the OPEN_DELEGATE_WRITE delegation in place, it is possible that the
            file was truncated during the duration of the delegation.  For
            example, the truncation could have occurred as a result of an
            OPEN UNCHECKED4 with a size attribute value of zero.  Therefore,
            if a truncation of the file has occurred and this operation has
            not been propagated to the server, the truncation must occur
            before any modified data is written to the server.
          </t>
        </list>
      </t>

      <t>
        In the case of an OPEN_DELEGATE_WRITE delegation, file
        locking imposes some additional requirements.  To precisely
        maintain the associated invariant, it is required to flush
        any modified data in any region for which a write lock was
        released while the OPEN_DELEGATE_WRITE delegation was in
        effect.  However, because the OPEN_DELEGATE_WRITE delegation
        implies no other locking by other clients, a simpler
        implementation is to flush all modified data for the file
        (as described just above) if any write lock has been released
        while the OPEN_DELEGATE_WRITE delegation was in effect.
      </t>

      <t>
        An implementation need not wait until delegation recall (or deciding
        to voluntarily return a delegation) to perform any of the above
        actions, if implementation considerations (e.g., resource availability
        constraints) make that desirable.  Generally, however, the fact that
        the actual open state of the file may continue to change makes it not
        worthwhile to send information about opens and closes to the server,
        except as part of delegation return.  Only in the case of closing the
        open that resulted in obtaining the delegation would clients be likely
        to do this early, since, in that case, the close once done will not
        be undone.  Regardless of the client's choices on scheduling these
        actions, all must be performed before the delegation is returned,
        including (when applicable) the close that corresponds to the open
        that resulted in the delegation.  These actions can be performed
        either in previous requests or in previous operations in the same
        COMPOUND request.
      </t>
    </section>

    <section title="OPEN Delegation Race with CB_RECALL">
      <t>
        The server informs the client of a recall via a CB_RECALL. A race
        case that may develop is when the delegation is immediately
        recalled before the COMPOUND that established the delegation
        is returned to the client. As the CB_RECALL provides both a
        stateid and a filehandle for which the client has no mapping,
        it cannot honor the recall attempt. At this point, the client has two
        choices: either do not respond or respond with NFS4ERR_BADHANDLE. 
        If it does not respond, then it runs the risk of the server
        deciding to not grant it further delegations.
      </t>

      <t>
        If instead it does reply with NFS4ERR_BADHANDLE, then both the
        client and the server might be able to  detect that a race condition
        is occurring.  The client can keep a list of pending delegations.
        When it receives a CB_RECALL for an unknown delegation, it can cache
        the stateid and filehandle on a list of pending recalls. When it
        is provided with a delegation, it would only use it if it was not
        on the pending recall list. Upon the next CB_RECALL, it could
        immediately return the delegation.
      </t>

      <t>
        In turn, the server can keep track of when it issues a delegation
        and assume that if a client responds to the CB_RECALL with an
        NFS4ERR_BADHANDLE, then the client has yet to receive the
        delegation.  The server SHOULD give the client a reasonable time
        both to get this delegation and to return it before revoking the
        delegation. Unlike a failed callback path, the server should
        periodically probe the client with CB_RECALL to see if it has
        received the delegation and is ready to return it.
      </t>

      <t>
        When the server finally determines that enough time has elapsed,
        it SHOULD revoke the delegation and it SHOULD NOT revoke the lease.
        During this extended recall process, the server SHOULD be
        renewing the client lease. The intent here is that the client
        not pay too onerous a burden for a condition caused by the server.
      </t>

    </section>

    <section title="Clients That Fail to Honor Delegation Recalls">

      <t>
        A client may fail to respond to a recall for various reasons, such as
        a failure of the callback path from the server to the client.
        The client may be unaware of a failure in the callback path.
        This lack of awareness could result in the client finding out
        long after the failure that its delegation has been revoked, and
        another client has modified the data for which the client had
        a delegation.  This is especially a problem for the client that
        held an OPEN_DELEGATE_WRITE delegation.
      </t>

      <t>
        The server also has a dilemma in that the client that fails to
        respond to the recall might also be sending other NFS requests,
        including those that renew the lease before the lease expires.
        Without returning an error for those lease-renewing operations,
        the server leads the client to believe that the delegation it has
        is in force.
      </t>

      <t>
        This difficulty is solved by the following rules:

        <list style='symbols'>
          <t>
            When the callback path is down, the server MUST NOT revoke the
            delegation if one of the following occurs:

            <list style='symbols'>
              <t>
                The client has issued a RENEW operation, and the server has
                returned an NFS4ERR_CB_PATH_DOWN error.  The server MUST renew
                the lease for any byte-range locks and share reservations the
                client has that the server has known about (as opposed to
                those locks and share reservations the client has established
                but not yet sent to the server, due to the delegation).
                The server SHOULD give the client a reasonable time to return
                its delegations to the server before revoking the client's
                delegations.
              </t>

              <t>
                The client has not issued a RENEW operation for some period of
                time after the server attempted to recall the delegation.
                This period of time MUST NOT be less than the value of the
                lease_time attribute.
              </t>
            </list>
          </t>

          <t>
            When the client holds a delegation, it cannot rely on operations,
            except for RENEW, that take a stateid, to renew delegation leases
            across callback path failures.  The client that wants to keep
            delegations in force across callback path failures must use RENEW
            to do so.
          </t>
        </list>
      </t>

    </section>
    <section title="Delegation Revocation">

      <t>
        At the point a delegation is revoked, if there are associated opens
        on the client, the applications holding these opens need to be
        notified.  This notification usually occurs by returning errors for
        READ/WRITE operations or when a close is attempted for the open file.
      </t>

      <t>
        If no opens exist for the file at the point the delegation is
        revoked, then notification of the revocation is unnecessary.
        However, if there is modified data present at the client for
        the file, the user of the application should be notified.
        Unfortunately, it may not be possible to notify the user
        since active applications may not be present at the client.
        See <xref target="ss:cc:rrwod" /> for additional details.
      </t>

    </section>
  </section>
  <section anchor="ss:cc:cache_revoke" title="Data Caching and Revocation">

    <t>
      When locks and delegations are revoked, the assumptions upon which
      successful caching depend are no longer guaranteed.  For any locks or
      share reservations that have been revoked, the corresponding owner
      needs to be notified.  This notification includes applications with a
      file open that has a corresponding delegation that has been revoked.
      Cached data associated with the revocation must be removed from the
      client.  In the case of modified data existing in the client's cache,
      that data must be removed from the client without it being written to
      the server.  As mentioned, the assumptions made by the client are no
      longer valid at the point when a lock or delegation has been revoked.
      For example, another client may have been granted a conflicting lock
      after the revocation of the lock at the first client.  Therefore, the
      data within the lock range may have been modified by the other client.
      Obviously, the first client is unable to guarantee to the application
      what has occurred to the file in the case of revocation.
    </t>

    <t>
      Notification to a lock-owner will in many cases consist of simply
      returning an error on the next and all subsequent READs/WRITEs to the
      open file or on the close.  Where the methods available to a client
      make such notification impossible because errors for certain
      operations may not be returned, more drastic action, such as signals
      or process termination, may be appropriate.  The justification for
      this is that an invariant on which an application depends may
      be violated.  Depending on how errors are typically treated for the
      client operating environment, further levels of notification, including
      logging, console messages, and GUI pop-ups, may be appropriate.
    </t>

    <section anchor="ss:cc:rrwod" title="Revocation Recovery for Write Open Delegation">

      <t>
        Revocation recovery for an OPEN_DELEGATE_WRITE delegation poses the
        special issue of modified data in the client cache while the file is
        not open.  In this situation, any client that does not flush modified
        data to the server on each close must ensure that the user receives
        appropriate notification of the failure as a result of the revocation.
        Since such situations may require human action to correct problems,
        notification schemes in which the appropriate user or administrator
        is notified may be necessary.  Logging and console messages are
        typical examples.
      </t>

      <t>
        If there is modified data on the client, it must not be flushed
        normally to the server.  A client may attempt to provide a copy of
        the file data as modified during the delegation under a different
        name in the file system namespace to ease recovery.  Note that when
        the client can determine that the file has not been modified by any
        other client, or when the client has a complete cached copy of the file
        in question, such a saved copy of the client's view of the file
        may be of particular value for recovery.  In other cases, recovery
        using a copy of the file, based partially on the client's cached
        data and partially on the server copy as modified by other clients,
        will be anything but straightforward, so clients may avoid saving
        file contents in these situations or mark the results specially to
        warn users of possible problems.
      </t>

      <t>
        The saving of such modified data in delegation revocation situations
        may be limited to files of a certain size or might be used only when
        sufficient disk space is available within the target file system.
        Such saving may also be restricted to situations when the client
        has sufficient buffering resources to keep the cached copy available
        until it is properly stored to the target file system.
      </t>

    </section>
  </section>
  <section title="Attribute Caching">

    <t>
      The attributes discussed in this section do not include named
      attributes.  Individual named attributes are analogous to files, and
      caching of the data for these needs to be handled just as data
      caching is for regular files.  Similarly, LOOKUP results from an
      OPENATTR directory are to be cached on the same basis as any other
      pathnames and similarly for directory contents.
    </t>

    <t>
      Clients may cache file attributes obtained from the server and use
      them to avoid subsequent GETATTR requests.  This cache is
      write through caching in that any modifications to the file
      attributes are always done by means of requests to the server,
      which means the modifications should not be done locally and should
      not be cached.  Exceptions to this are modifications to attributes
      that are intimately connected with data caching.  Therefore, extending
      a file by writing data to the local data cache is reflected
      immediately in the size as seen on the client without this change
      being immediately reflected on the server.  Normally, such changes are
      not propagated directly to the server, but when the modified data is
      flushed to the server, analogous attribute changes are made on the
      server.  When open delegation is in effect, the modified attributes
      may be returned to the server in the response to a CB_GETATTR call.
    </t>

    <t>
      The result of local caching of attributes is that the attribute
      caches maintained on individual clients will not be coherent.
      Changes made in one order on the server may be seen in a different
      order on one client and in a third order on a different client.
    </t>

    <t>
      The typical file system application programming interfaces do not
      provide means to atomically modify or interrogate attributes for
      multiple files at the same time.  The following rules provide an
      environment where the potential incoherency mentioned above can be
      reasonably managed.  These rules are derived from the practice of
      previous NFS protocols.

      <list style='symbols'>
        <t>
          All attributes for a given file (per-fsid attributes excepted) are
          cached as a unit at the client so that no non-serializability
          can arise within the context of a single file.
        </t>

        <t>
          An upper time boundary is maintained on how long a client cache
          entry can be kept without being refreshed from the server.
        </t>

        <t>
          When operations are performed that modify attributes at the
          server, the updated attribute set is requested as part of the
          containing RPC.  This includes directory operations that update
          attributes indirectly.  This is accomplished by following the
          modifying operation with a GETATTR operation and then using the
          results of the GETATTR to update the client's cached attributes.
        </t>
      </list>
    </t>

    <t>
      Note that if the full set of attributes to be cached is requested by
      READDIR, the results can be cached by the client on the same basis
      as attributes obtained via GETATTR.
    </t>

    <t>
      A client may validate its cached version of attributes for a file by
      only fetching both the change and time_access attributes and assuming
      that if the change attribute has the same value as it did when the
      attributes were cached, then no attributes other than time_access
      have changed.  The time_access attribute is also fetched because
      many servers operate in environments where the operation
      that updates change does not update time_access.  For example, POSIX
      file semantics do not update access time when a file is modified by
      the write system call.  Therefore, the client that wants a current
      time_access value should fetch it with change during the attribute
      cache validation processing and update its cached time_access.
    </t>

    <t>
      The client may maintain a cache of modified attributes for those
      attributes intimately connected with data of modified regular files
      (size, time_modify, and change).  Other than those three attributes,
      the client MUST NOT maintain a cache of modified attributes.
      Instead, attribute changes are immediately sent to the server.
    </t>

    <t>
      In some operating environments, the equivalent to time_access is
      expected to be implicitly updated by each read of the content of the
      file object.  If an NFS client is caching the content of a file
      object, whether it is a regular file, directory, or symbolic link,
      the client SHOULD NOT update the time_access attribute (via SETATTR
      or a small READ or READDIR request) on the server with each read that
      is satisfied from cache.  The reason is that this can defeat the
      performance benefits of caching content, especially since an explicit
      SETATTR of time_access may alter the change attribute on the server.
      If the change attribute changes, clients that are caching the content
      will think the content has changed and will re-read unmodified data
      from the server.  Nor is the client encouraged to maintain a modified
      version of time_access in its cache, since this would mean that the
      client either will eventually have to write the access time to the
      server with bad performance effects or would never update the
      server's time_access, thereby resulting in a situation where an
      application that caches access time between a close and open of the
      same file observes the access time oscillating between the past and
      present.  The time_access attribute always means the time of last
      access to a file by a READ that was satisfied by the server.
      This way, clients will tend to see only time_access changes that
      go forward in time.
    </t>

  </section>
  <section title="Data and Metadata Caching and Memory-Mapped Files">

    <t>
      Some operating environments include the capability for an application
      to map a file's content into the application's address space.  Each
      time the application accesses a memory location that corresponds to a
      block that has not been loaded into the address space, a page
      fault occurs and the file is read (or if the block does not exist
      in the file, the block is allocated and then instantiated in the
      application's address space).
    </t>

    <t>
      As long as each memory-mapped access to the file requires a page
      fault, the relevant attributes of the file that are used to detect
      access and modification (time_access, time_metadata, time_modify,
      and change) will be updated.  However, in many operating environments,
      when page faults are not required, these attributes will not be updated
      on reads or updates to the file via memory access (regardless of whether
      the file is a local file or is being accessed remotely).  A client or
      server MAY fail to update attributes of a file that is being accessed
      via memory-mapped I/O.  This has several implications:

      <list style='symbols'>
        <t>
          If there is an application on the server that has memory mapped a
          file that a client is also accessing, the client may not be able
          to get a consistent value of the change attribute to determine
          whether its cache is stale or not.  A server that knows that
          the file is memory mapped could always pessimistically return
          updated values for change so as to force the application to
          always get the most up-to-date data and metadata for the file.
          However, due to the negative performance implications of this,
          such behavior is OPTIONAL.
        </t>

        <t>
          If the memory-mapped file is not being modified on the server and
          instead is just being read by an application via the
          memory-mapped interface, the client will not see an updated
          time_access attribute.  However, in many operating environments,
          neither will any process running on the server.  Thus, NFS
          clients are at no disadvantage with respect to local processes.
        </t>

        <t>
          If there is another client that is memory mapping the file
          and if that client is holding an OPEN_DELEGATE_WRITE delegation,
          the same set of issues as discussed in the previous two bullet
          items apply.  So, when a server does a CB_GETATTR to a file
          that the client has modified in its cache, the response
          from CB_GETATTR will not necessarily be accurate.  As
          discussed earlier, the client's obligation is to report that
          the file has been modified since the delegation was granted,
          not whether it has been modified again between successive
          CB_GETATTR calls, and the server MUST assume that any file the
          client has modified in cache has been modified again between
          successive CB_GETATTR calls.  Depending on the nature of the
          client's memory management system, this weak obligation may not
          be possible.  A client MAY return stale information in CB_GETATTR
          whenever the file is memory mapped.
        </t>

        <t>
          The mixture of memory mapping and file locking on the same file is
          problematic.  Consider the following scenario, where the page size
          on each client is 8192 bytes.

          <list style='symbols'>
            <t>
              Client A memory maps first page (8192 bytes) of file X.
            </t>

            <t>
              Client B memory maps first page (8192 bytes) of file X.
            </t>

            <t>
              Client A write locks first 4096 bytes.
            </t>

            <t>
              Client B write locks second 4096 bytes.
            </t>

            <t>
              Client A, via a STORE instruction, modifies part of its
              locked region.
            </t>

            <t>
              Simultaneous to client A, client B issues a STORE on part of
              its locked region.
            </t>
          </list>
        </t>
      </list>
    </t>

    <t>
      Here, the challenge is for each client to resynchronize to get a
      correct view of the first page.  In many operating environments, the
      virtual memory management systems on each client only know a page is
      modified, not that a subset of the page corresponding to the
      respective lock regions has been modified.  So it is not possible
      for each client to do the right thing, which is to only write to
      the server that portion of the page that is locked. For example,
      if client A simply writes out the page, and then client B writes
      out the page, client A's data is lost.
    </t>

    <t>
      Moreover, if mandatory locking is enabled on the file, then we have a
      different problem.  When clients A and B issue the STORE instructions,
      the resulting page faults require a byte-range lock on the entire page.
      Each client then tries to extend their locked range to the entire
      page, which results in a deadlock.
    </t>

    <t>
      Communicating the NFS4ERR_DEADLOCK error to a STORE instruction is
      difficult at best.
    </t>

    <t>
      If a client is locking the entire memory-mapped file, there is no
      problem with advisory or mandatory byte-range locking, at least until
      the client unlocks a region in the middle of the file.
    </t>

    <t>
      Given the above issues, the following are permitted:

      <list style='symbols'>
        <t>
          Clients and servers MAY deny memory mapping a file they know
          there are byte-range locks for.
        </t>

        <t>
          Clients and servers MAY deny a byte-range lock on a file they know is
          memory mapped.
        </t>

        <t>
          A client MAY deny memory mapping a file that it knows requires
          mandatory locking for I/O.  If mandatory locking is enabled after
          the file is opened and mapped, the client MAY deny the application
          further access to its mapped file.
        </t>
      </list>
    </t>

  </section>
  <section title="Name Caching">

    <t>
      The results of LOOKUP and READDIR operations may be cached to avoid
      the cost of subsequent LOOKUP operations.  Just as in the case of
      attribute caching, inconsistencies may arise among the various client
      caches.  To mitigate the effects of these inconsistencies and given
      the context of typical file system APIs, an upper time boundary is
      maintained on how long a client name cache entry can be kept without
      verifying that the entry has not been made invalid by a directory
      change operation performed by another client.
    </t>

    <t>
      When a client is not making changes to a directory for which there
      exist name cache entries, the client needs to periodically fetch
      attributes for that directory to ensure that it is not being
      modified.  After determining that no modification has occurred,
      the expiration time for the associated name cache entries may be
      updated to be the current time plus the name cache staleness bound.
    </t>

    <t>
      When a client is making changes to a given directory, it needs to
      determine whether there have been changes made to the directory by
      other clients.  It does this by using the change attribute as
      reported before and after the directory operation in the associated
      change_info4 value returned for the operation.  The server is able to
      communicate to the client whether the change_info4 data is provided
      atomically with respect to the directory operation.  If the change
      values are provided atomically, the client is then able to compare
      the pre-operation change value with the change value in the client's
      name cache.  If the comparison indicates that the directory was
      updated by another client, the name cache associated with the modified
      directory is purged from the client.  If the comparison indicates
      no modification, the name cache can be updated on the client to
      reflect the directory operation and the associated timeout extended.
      The post-operation change value needs to be saved as the basis for
      future change_info4 comparisons.
    </t>

    <t>
      As demonstrated by the scenario above, name caching requires that the
      client revalidate name cache data by inspecting the change attribute
      of a directory at the point when the name cache item was cached.
      This requires that the server update the change attribute for
      directories when the contents of the corresponding directory
      are modified.  For a client to use the change_info4 information
      appropriately and correctly, the server must report the
      pre- and post-operation change attribute values atomically.  When
      the server is unable to report the before and after values
      atomically with respect to the directory operation, the server must
      indicate that fact in the change_info4 return value.  When
      the information is not atomically reported, the client should not
      assume that other clients have not changed the directory.
    </t>

  </section>
  <section title="Directory Caching">

    <t>
      The results of READDIR operations may be used to avoid subsequent
      READDIR operations.  Just as in the cases of attribute and name
      caching, inconsistencies may arise among the various client caches.
      To mitigate the effects of these inconsistencies, and given the
      context of typical file system APIs, the following rules should be
      followed:

      <list style='symbols'>
        <t>
          Cached READDIR information for a directory that is not obtained
          in a single READDIR operation must always be a consistent snapshot
          of directory contents.  This is determined by using a GETATTR
          before the first READDIR and after the last READDIR that
          contributes to the cache.
        </t>

        <t>
          An upper time boundary is maintained to indicate the length of
          time a directory cache entry is considered valid before the client
          must revalidate the cached information.
        </t>
      </list>
    </t>

    <t>
      The revalidation technique parallels that discussed in the case
      of name caching.  When the client is not changing the directory in
      question, checking the change attribute of the directory with GETATTR
      is adequate.  The lifetime of the cache entry can be extended at
      these checkpoints.  When a client is modifying the directory, the
      client needs to use the change_info4 data to determine whether there
      are other clients modifying the directory.  If it is determined that
      no other client modifications are occurring, the client may update
      its directory cache to reflect its own changes.
    </t>

    <t>
      As demonstrated previously, directory caching requires that the client
      revalidate directory cache data by inspecting the change attribute of
      a directory at the point when the directory was cached.  This requires
      that the server update the change attribute for directories when the
      contents of the corresponding directory are modified.  For a client
      to use the change_info4 information appropriately and correctly,
      the server must report the pre- and post-operation change attribute
      values atomically.  When the server is unable to report the before
      and after values atomically with respect to the directory operation,
      the server must indicate that fact in the change_info4 return value.
      When the information is not atomically reported, the client should
      not assume that other clients have not changed the directory.
    </t>

  </section>
</section>

<section anchor="sec:minor" title="Minor Versioning">
  <t>
   To address the requirement of an NFS protocol that can evolve as the
   need arises, the NFSv4 protocol contains the rules and
   framework to allow for future minor changes or versioning.
  </t>

  <t>
   The base assumption with respect to minor versioning is that any
   future accepted minor version must follow the IETF process and be
   documented in a Standards Track RFC.  Therefore, each minor version
   number will correspond to an RFC.  Minor version 0 of the
   NFSv4 protocol is represented by this RFC.  The COMPOUND
   and CB_COMPOUND procedures support the encoding of the minor version
   being requested by the client.
  </t>

  <t>
    Future minor versions will extend, rather than replace, the XDR
    for the preceding minor version, as had been done in moving
    from NFSv2 to NFSv3 and from NFSv3 to NFSv4.0.
  </t>

  <t>
    Specification of detailed rules for the construction of minor
    versions will be addressed in documents defining early minor
    versions or, more desirably, in an RFC establishing a versioning
    framework for NFSv4 as a whole.
  </t>
</section>

<section anchor="sec:i18n" title="Internationalization">
  <section anchor="ss:i18n:intro" title="Introduction">
    <t>
      Internationalization is a complex topic with its own set of
      terminology (see <xref target='RFC6365' />).  The topic is
      made more complex in NFSv4.0 by the tangled history and state
      of NFS implementations.  This section describes what we might
      call "NFSv4.0 internationalization" (i.e., internationalization
      as implemented by existing clients and servers) as the basis
      upon which NFSv4.0 clients may implement internationalization
      support.
    </t>

    <t>
      This section is based on the behavior of existing implementations.
      Note that the behaviors described are each demonstrated by a
      combination of an NFSv4 server implementation proper and a
      server-side physical file system. It is common for servers
      and physical file systems to be configurable as to the behavior shown.
      In the discussion below, each configuration that shows different
      behavior is considered separately.
    </t>

    <t>
      Note that in this section, the key words "MUST", "SHOULD", and
      "MAY" retain their normal meanings.  However, in deriving
      this specification from implementation patterns, we document
      below how the normative terms used derive from the behavior
      of existing implementations, in those situations in which
      existing implementation behavior patterns can be determined.

      <list style='symbols'>
        <t>
          Behavior implemented by all existing clients or servers is described
          using "MUST", since new implementations need to follow existing
          ones to be assured of interoperability.  While it is possible that
          different behavior might be workable, we have found no case where
          this seems reasonable.
          <vspace blankLines='1' />
          The converse holds for "MUST NOT": if a type of behavior poses
          interoperability problems, it MUST NOT be implemented by any
          existing clients or servers. 
        </t>

        <t>
          Behavior implemented by most existing clients or servers, where
          that behavior is more desirable than any alternative, is described
          using "SHOULD", since new implementations need to follow that
          existing practice unless there are strong reasons to do otherwise.
          <vspace blankLines='1' />
          The converse holds for "SHOULD NOT".
        </t>

        <t>
          Behavior implemented by some, but not all, existing clients or
          servers is described using "MAY", indicating that new
          implementations have a choice as to whether they will behave
          in that way.  Thus, new implementations will have the same
          flexibility that existing ones do.
        </t>

        <t>
          Behavior implemented by all existing clients or servers, so far
          as is known -- but where there remains some uncertainty as to
          details -- is described using "should".  Such cases primarily
          concern details of error returns.  New implementations should
          follow existing practice even though such situations generally
          do not affect interoperability.
        </t>
      </list>
    </t>

    <t>
      There are also cases in which certain server behaviors, while
      not known to exist, cannot be reliably determined not to
      exist.  In part, this is a consequence of the long period of
      time that has elapsed since the publication of <xref target='RFC3530' />,
      resulting in a situation in which those involved in the
      implementation may no longer be involved in or aware of working
      group activities.
    </t>

    <t>
      In the case of possible server behavior that is neither known
      to exist nor known not to exist, we use "SHOULD NOT" and
      "MUST NOT" as follows, and similarly for "SHOULD" and "MUST".

      <list style='symbols'>
        <t>
          In some cases, the potential behavior is not known to exist but is
          of such a nature that, if it were in fact implemented,
          interoperability difficulties would be expected and reported,
          giving us cause to conclude that the potential behavior is not
          implemented.  For such behavior, we use "MUST NOT".
          Similarly, we use "MUST" to apply to the contrary behavior.
        </t>

        <t>
          In other cases, potential behavior is not known to exist but the
          behavior, while undesirable, is not of such a nature that we are
          able to draw any conclusions about its potential existence.  In
          such cases, we use "SHOULD NOT". Similarly, we use "SHOULD"
          to apply to the contrary behavior.
        </t>
      </list>
    </t>

    <t>
      In the case of a "MAY", "SHOULD", or "SHOULD NOT" that applies to
      servers, clients need to be aware that there are servers that
      may or may not take the specified action, and they need to
      be prepared for either eventuality.
    </t>
  </section>

  <section anchor="ss:i18n:limits" title="Limitations on Internationalization-Related Processing in the NFSv4 Context">
    <t>
      There are a number of noteworthy circumstances that limit the degree
      to which internationalization-related processing can be made universal
      with regard to NFSv4 clients and servers:

      <list style='symbols'>
        <t>
          The NFSv4 client is part of an extensive set of client-side software
          components whose design and internal interfaces are not within the
          IETF's purview, limiting the degree to which a particular character
          encoding may be made standard.
        </t>
        <t>
          Server-side handling of file component names is typically
          implemented within a server-side physical file system, whose
          handling of character encoding and normalization is not specifiable by the IETF.
        </t>
        <t>
          Typical implementation patterns in UNIX systems result in the
          NFSv4 client having no knowledge of the character encoding being
          used, which may even vary between processes on the same client
          system.
        </t>
        <t>
          Users may need access to files stored previously with non-UTF-8
          encodings, or with UTF-8 encodings that do not match any particular normalization form.
        </t>
      </list>
    </t>
  </section>

  <section anchor="ss:i18n:servsum" title="Summary of Server Behavior Types">
    <t>
      As mentioned in <xref target='ss:i18n:types' />, servers MAY
      reject component name strings that are not valid UTF-8.  This
      leads to a number of types of valid server behavior, as
      outlined below.  When these are combined with
      the valid normalization-related behaviors as described in <xref target='ss:i18n:encode' />,
      this leads to the combined behaviors outlined below.

      <list style='symbols'>
        <t>
                Servers that limit file component names to UTF-8
                strings exist with normalization-related
                handling as described
                in <xref target='ss:i18n:encode' />.  These are best
                described as "UTF-8-only servers".
        </t>

        <t>
                Servers that do not limit file component names to UTF-8
                strings are very common and are necessary to deal with
                clients/applications not oriented to the use of UTF-8.
                Such servers ignore normalization-related issues, and there
                is no way for them to implement either normalization or
                representation-independent lookups.  These are best
                described as "UTF-8-unaware servers", since they treat
                file component names as uninterpreted strings of bytes
                and have no knowledge of the characters represented.
                See <xref target='ss:i18n:utf8_err' /> for details.
        </t>

        <t>
          It is possible for a server to allow component names that
          are not valid UTF-8, while still being aware of the
          structure of UTF-8 strings.  Such servers could implement
          either normalization or representation-independent lookups
          but apply those techniques only to valid UTF-8 strings.
          Such servers are not common, but it is possible to configure at
          least one known server to have this behavior.  This behavior
          SHOULD NOT be used due to the possibility that a filename
          using one character set may, by coincidence, have the appearance
          of a UTF-8 filename; the results of UTF-8 normalization or
          representation-independent lookups are unlikely to be correct
          in all cases with respect to the other character set.
        </t>
      </list>
    </t>
  </section>

  <section anchor="ss:i18n:encode" title="String Encoding">
    <t>
      Strings that potentially contain characters outside the ASCII range
      <xref target='RFC20' /> are generally represented in NFSv4 using
      the UTF-8 encoding <xref target='RFC3629' /> of Unicode
      <xref target='UNICODE' />.  See <xref target='RFC3629' /> for
      precise encoding and decoding rules.
    </t>

    <t>
      Some details of the protocol treatment depend on the type of string:

      <list style='symbols'>
        <t>
          For strings that are component names, the preferred encoding for any
          non-ASCII characters is the UTF-8 representation of Unicode.
          <vspace blankLines='1' />

          In many cases, clients have no knowledge of the encoding
          being used, with the encoding done at the user level under
          the control of a per-process locale specification. As a result,
          it may be impossible for the NFSv4 client to enforce the
          use of UTF-8. The use of non-UTF-8 encodings can be
          problematic, since it may interfere with access to files
          stored using other forms of name encoding. Also,
          normalization-related
          processing (see <xref target='ss:i18n:norms' />) of a string
          not encoded in UTF-8 could result in inappropriate name
          modification or aliasing.  In cases in which one has a
          non-UTF-8 encoded name that accidentally conforms to
          UTF-8 rules, substitution of canonically equivalent strings
          can change the non-UTF-8 encoded name drastically.
          <vspace blankLines='1' />

          The kinds of modification and aliasing mentioned here can
          lead to both false negatives and false positives, depending on
          the strings in question, which can result in security
          issues such as elevation of privilege and denial of service
          (see <xref target='RFC6943' /> for further discussion).
        </t>

        <t>
          For strings based on domain names, non-ASCII characters MUST be
          represented using the UTF-8 encoding of Unicode, and additional
          string format restrictions apply.
          See <xref target='ss:i18n:types' /> for details.
        </t>

        <t>
          The contents of symbolic links (of type linktext4 in the
          XDR) MUST be treated as opaque data by NFSv4 servers.
          Although UTF-8 encoding is often used, it need not be.
          In this respect, the contents of symbolic links are like
          the contents of regular files in that their encoding is
          not within the scope of this specification.
        </t>

        <t>
          For other sorts of strings, any non-ASCII characters SHOULD be
          represented using the UTF-8 encoding of Unicode.
        </t>
      </list>
    </t>
  </section>

  <section anchor="ss:i18n:norms" title="Normalization">
    <t>
      The client and server operating environments may differ in their
      policies and operational methods with respect to character
      normalization (see <xref target="UNICODE" /> for a discussion of
      normalization forms).  This difference may also exist between
      applications on the
      same client.  This adds to the difficulty of providing a single
      normalization policy for the protocol that allows for maximal
      interoperability.  This issue is similar to the issues of
      character case where the server may or may not support
      case-insensitive filename matching and may or may not preserve
      the character case when storing filenames.  The protocol does not
      mandate a particular behavior but allows for a range of useful
      behaviors.
    </t>

    <t>
      The NFSv4 protocol does not mandate the use of a particular
      normalization form at this time.  A subsequent minor version of
      the NFSv4 protocol might specify a particular normalization form.
      Therefore, the server and client can expect that they may receive
      unnormalized characters within protocol requests and responses.  If
      the operating environment requires normalization, then the
      implementation will need to normalize the various UTF-8 encoded strings
      within the protocol before presenting the information to an
      application (at the client) or local file system (at the server).
    </t>

    <t>
      Server implementations MAY normalize filenames to conform
      to a particular normalization form before using the resulting
      string when looking up or creating a file.  Servers MAY also
      perform normalization-insensitive string comparisons without
      modifying the names to match a particular normalization form.
      Except in cases in which component names are excluded from
      normalization-related handling because they are not valid
      UTF-8 strings, a server MUST make the same choice (as to
      whether to normalize or not, the target form of normalization,
      and whether to do normalization-insensitive string comparisons)
      in the same way for all accesses to a particular file system.
      Servers SHOULD NOT reject a filename because it does not
      conform to a particular normalization form, as this may deny
      access to clients that use a different normalization form.
    </t>
  </section>

  <section anchor="ss:i18n:types" title="Types with Processing Defined by Other Internet Areas">
    <t>
      There are two types of strings that NFSv4 deals with that are based
      on domain names.  Processing of such strings is defined by other
      Internet standards, and hence the processing behavior for such
      strings should be consistent across all server operating systems
      and server file systems.
    </t>

    <t>
      These are as follows:

      <list style='symbols'>
        <t>
          Server names as they appear in the fs_locations attribute.  Note
          that for most purposes, such server names will only be sent by the
          server to the client.  The exception is the use of the
          fs_locations attribute in a VERIFY or NVERIFY operation.
        </t>

        <t>
          Principal suffixes that are used to denote sets of users and
          groups, and are in the form of domain names.
        </t>
      </list>
    </t>

    <t>
      The general rules for handling all of these domain-related strings
      are similar and independent of the role of the sender or receiver as
      client or server, although the consequences of failure to obey these
      rules may be different for client or server.  The server can report
      errors when it is sent invalid strings, whereas the client will
      simply ignore invalid string or use a default value in their place.
    </t>

    <t>
      The string sent SHOULD be in the form of one or more U-labels
      as defined by <xref target='RFC5890' />. If that is impractical,
      it can instead be in the form of one or more LDH labels <xref target='RFC5890' /> or a UTF-8 domain name that
      contains labels that are not properly formatted U-labels. The receiver
      needs to be able to accept domain and server names in any of
      the formats allowed. The server MUST reject, using the error
      NFS4ERR_INVAL, a string that is not valid UTF-8, or that
      contains an ASCII label that is not a valid LDH label, or
      that contains an XN&nbhy;label (begins with "xn--") for which the
      characters after "xn--" are not valid output of the Punycode
      algorithm <xref target='RFC3492' />.
    </t>

    <t>
      When a domain string is part of id@domain or group@domain, there are
      two possible approaches:

      <list style='numbers'>
        <t>
          The server treats the domain string as a series of U-labels.
          In cases where the domain string is a series of A-labels
          or Non&nbhy;Reserved LDH (NR-LDH) labels, it converts them to
          U-labels using the Punycode algorithm <xref target='RFC3492' />.
          In cases where the domain string is a series of other sorts of
          LDH labels, the server can use the ToUnicode function defined
          in <xref target='RFC3490' /> to convert the string to a
          series of labels that generally conform to the U-label
          syntax. In cases where the domain string is a UTF-8 string
          that contains non-U-labels, the server can attempt to use
          the ToASCII function defined in <xref target='RFC3490' />
          and then the ToUnicode function on the string to convert
          it to a series of labels that generally conform to the
          U-label syntax. As a result, the domain string returned
          within a user id on a GETATTR may not match that sent when
          the user id is set using SETATTR, although when this
          happens, the domain will be in the form that generally
          conforms to the U-label syntax.
        </t>

        <t>
          The server does not attempt to treat the domain string
          as a series of U-labels; specifically, it does not map a
          domain string that is not a U-label into a U-label using
          the methods described above. As a result, the domain
          string returned on a GETATTR of the user id MUST be the
          same as that used when setting the user&nbsp;id by the SETATTR.
        </t>
      </list>

      A server SHOULD use the first method.
    </t>

    <t>
      For VERIFY and NVERIFY, additional string processing requirements
      apply to verification of the owner and owner_group attributes;
      see <xref target='sec:fattr:owner_group' />.
    </t>
  </section>

  <section anchor="ss:i18n:utf8_err" title="Errors Related to UTF-8">
    <t>
      Where the client sends an invalid UTF-8 string, the server MAY
      return an NFS4ERR_INVAL error.  This includes cases in which
      inappropriate prefixes are detected and where the count includes
      trailing bytes that do not constitute a full Universal Multiple-Octet
      Coded Character Set (UCS) character.
    </t>

    <t>
      Requirements for server handling of component names that are not
      valid UTF-8, when a server does not return NFS4ERR_INVAL in response
      to receiving them, are described in <xref target='ss:i18n:nonvalid' />.
    </t>

    <t>
      Where the string supplied by the client is not rejected with
      NFS4ERR_INVAL but contains characters that are not supported
      by the server as a value for that string (e.g., names containing
      slashes, or characters that do not fit into 16 bits when
      converted from UTF-8 to a Unicode codepoint), the server
      should return an NFS4ERR_BADCHAR error.
    </t>

    <t>
      Where a UTF-8 string is used as a filename, and the file
      system, while supporting all of the characters within the
      name, does not allow that particular name to be used, the
      server should return the error NFS4ERR_BADNAME.  This includes
      such situations as file system prohibitions of "." and ".."
      as filenames for certain operations, and similar constraints.
    </t>
  </section>

  <section anchor="ss:i18n:nonvalid" title="Servers That Accept File Component Names That Are Not Valid UTF-8 Strings">
    <t>
      As stated previously, servers MAY accept, on all or on some
      subset of the physical file systems exported, component names
      that are not valid UTF-8 strings.  A typical pattern is for
      a server to use UTF&nbhy;8-unaware physical file systems that treat
      component names as uninterpreted strings of bytes, rather
      than having any awareness of the character set being used.
    </t>

    <t>
      Such servers SHOULD NOT change the stored representation of
      component names from those received on the wire and SHOULD
      use an octet-by-octet comparison of component name strings
      to determine equivalence (as opposed to any broader notion
      of string comparison).  This is because the server has no
      knowledge of the character encoding being used.
    </t>

    <t>
      Nonetheless, when such a server uses a broader notion of
      string equivalence than what is recommended in the
      preceding paragraph, the following considerations apply:

      <list style='symbols'>
        <t>
          Outside of 7-bit ASCII, string processing that changes string
          contents is usually specific to a character set and hence is
          generally unsafe when the character set is unknown.  This
          processing could change the filename in an unexpected fashion,
          rendering the file inaccessible to the application or client that
          created or renamed the file and to others expecting the original
          filename.  Hence, such processing should not be performed,
          because doing so is likely to result in incorrect string
          modification or aliasing.
        </t>

        <t>
          Unicode normalization is particularly dangerous, as such
          processing assumes that the string is UTF-8.  When that assumption
          is false because a different character set was used to create the
          filename, normalization may corrupt the filename with respect to
          that character set, rendering the file inaccessible to the
          application that created it and others expecting the original
          filename.  Hence, Unicode normalization SHOULD NOT be performed,
          because it may cause incorrect string modification or aliasing.
        </t>
      </list>

      When the above recommendations are not followed, the resulting
      string modification and aliasing can lead to both false negatives
      and false positives, depending on the strings in question, which can
      result in security issues such as elevation of privilege and
      denial of service (see <xref target='RFC6943' /> for further discussion).
    </t>
  </section>
</section>

<section title="Error Values">
  <t>
    NFS error numbers are assigned to failed operations within a
    COMPOUND or CB_COMPOUND request.  A COMPOUND request
    contains a number of NFS operations that have their results
    encoded in sequence in a COMPOUND reply.  The results of successful
    operations will consist of an NFS4_OK status followed by the
    encoded results of the operation.  If an NFS operation fails, an
    error status will be entered in the reply, and the COMPOUND request
    will be terminated.
  </t>
  <section title="Error Definitions">
    <texttable anchor='error_definitions' title="Protocol Error Definitions">
      <ttcol align='left'>Error</ttcol>
      <ttcol align='left'>Number</ttcol>
      <ttcol align='left'>Description</ttcol>

      <c>NFS4_OK</c>
      <c>0</c>
      <c><xref target="err_OK" /></c>

      <c>NFS4ERR_ACCESS</c>
      <c>13</c>
      <c><xref target="err_ACCESS" /></c>

      <c>NFS4ERR_ADMIN_REVOKED</c>
      <c>10047</c>
      <c><xref target="err_ADMIN_REVOKED" /></c>

      <c>NFS4ERR_ATTRNOTSUPP</c>
      <c>10032</c>
      <c><xref target="err_ATTRNOTSUPP" /></c>

      <c>NFS4ERR_BADCHAR</c>
      <c>10040</c>
      <c><xref target="err_BADCHAR" /></c>

      <c>NFS4ERR_BADHANDLE</c>
      <c>10001</c>
      <c><xref target="err_BADHANDLE" /></c>

      <c>NFS4ERR_BADNAME</c>
      <c>10041</c>
      <c><xref target="err_BADNAME" /></c>

      <c>NFS4ERR_BADOWNER</c>
      <c>10039</c>
      <c><xref target="err_BADOWNER" /></c>

      <c>NFS4ERR_BADTYPE</c>
      <c>10007</c>
      <c><xref target="err_BADTYPE" /></c>

      <c>NFS4ERR_BADXDR</c>
      <c>10036</c>
      <c><xref target="err_BADXDR" /></c>

      <c>NFS4ERR_BAD_COOKIE</c>
      <c>10003</c>
      <c><xref target="err_BAD_COOKIE" /></c>

      <c>NFS4ERR_BAD_RANGE</c>
      <c>10042</c>
      <c><xref target="err_BAD_RANGE" /></c>

      <c>NFS4ERR_BAD_SEQID</c>
      <c>10026</c>
      <c><xref target="err_BAD_SEQID" /></c>

      <c>NFS4ERR_BAD_STATEID</c>
      <c>10025</c>
      <c><xref target="err_BAD_STATEID" /></c>

      <c>NFS4ERR_CB_PATH_DOWN</c>
      <c>10048</c>
      <c><xref target="err_CB_PATH_DOWN" /></c>

      <c>NFS4ERR_CLID_INUSE</c>
      <c>10017</c>
      <c><xref target="err_CLID_INUSE" /></c>

      <c>NFS4ERR_DEADLOCK</c>
      <c>10045</c>
      <c><xref target="err_DEADLOCK" /></c>

      <c>NFS4ERR_DELAY</c>
      <c>10008</c>
      <c><xref target="err_DELAY" /></c>

      <c>NFS4ERR_DENIED</c>
      <c>10010</c>
      <c><xref target="err_DENIED" /></c>

      <c>NFS4ERR_DQUOT</c>
      <c>69</c>
      <c><xref target="err_DQUOT" /></c>

      <c>NFS4ERR_EXIST</c>
      <c>17</c>
      <c><xref target="err_EXIST" /></c>

      <c>NFS4ERR_EXPIRED</c>
      <c>10011</c>
      <c><xref target="err_EXPIRED" /></c>

      <c>NFS4ERR_FBIG</c>
      <c>27</c>
      <c><xref target="err_FBIG" /></c>

      <c>NFS4ERR_FHEXPIRED</c>
      <c>10014</c>
      <c><xref target="err_FHEXPIRED" /></c>

      <c>NFS4ERR_FILE_OPEN</c>
      <c>10046</c>
      <c><xref target="err_FILE_OPEN" /></c>

      <c>NFS4ERR_GRACE</c>
      <c>10013</c>
      <c><xref target="err_GRACE" /></c>

      <c>NFS4ERR_INVAL</c>
      <c>22</c>
      <c><xref target="err_INVAL" /></c>

      <c>NFS4ERR_IO</c>
      <c>5</c>
      <c><xref target="err_IO" /></c>

      <c>NFS4ERR_ISDIR</c>
      <c>21</c>
      <c><xref target="err_ISDIR" /></c>

      <c>NFS4ERR_LEASE_MOVED</c>
      <c>10031</c>
      <c><xref target="err_LEASE_MOVED" /></c>

      <c>NFS4ERR_LOCKED</c>
      <c>10012</c>
      <c><xref target="err_LOCKED" /></c>

      <c>NFS4ERR_LOCKS_HELD</c>
      <c>10037</c>
      <c><xref target="err_LOCKS_HELD" /></c>

      <c>NFS4ERR_LOCK_NOTSUPP</c>
      <c>10043</c>
      <c><xref target="err_LOCK_NOTSUPP" /></c>

      <c>NFS4ERR_LOCK_RANGE</c>
      <c>10028</c>
      <c><xref target="err_LOCK_RANGE" /></c>

      <c>NFS4ERR_MINOR_VERS_MISMATCH</c>
      <c>10021</c>
      <c><xref target="err_MINOR_VERS_MISMATCH" /></c>

      <c>NFS4ERR_MLINK</c>
      <c>31</c>
      <c><xref target="err_MLINK" /></c>

      <c>NFS4ERR_MOVED</c>
      <c>10019</c>
      <c><xref target="err_MOVED" /></c>

      <c>NFS4ERR_NAMETOOLONG</c>
      <c>63</c>
      <c><xref target="err_NAMETOOLONG" /></c>

      <c>NFS4ERR_NOENT</c>
      <c>2</c>
      <c><xref target="err_NOENT" /></c>

      <c>NFS4ERR_NOFILEHANDLE</c>
      <c>10020</c>
      <c><xref target="err_NOFILEHANDLE" /></c>

      <c>NFS4ERR_NOSPC</c>
      <c>28</c>
      <c><xref target="err_NOSPC" /></c>

      <c>NFS4ERR_NOTDIR</c>
      <c>20</c>
      <c><xref target="err_NOTDIR" /></c>

      <c>NFS4ERR_NOTEMPTY</c>
      <c>66</c>
      <c><xref target="err_NOTEMPTY" /></c>

      <c>NFS4ERR_NOTSUPP</c>
      <c>10004</c>
      <c><xref target="err_NOTSUPP" /></c>

      <c>NFS4ERR_NOT_SAME</c>
      <c>10027</c>
      <c><xref target="err_NOT_SAME" /></c>

      <c>NFS4ERR_NO_GRACE</c>
      <c>10033</c>
      <c><xref target="err_NO_GRACE" /></c>

      <c>NFS4ERR_NXIO</c>
      <c>6</c>
      <c><xref target="err_NXIO" /></c>

      <c>NFS4ERR_OLD_STATEID</c>
      <c>10024</c>
      <c><xref target="err_OLD_STATEID" /></c>

      <c>NFS4ERR_OPENMODE</c>
      <c>10038</c>
      <c><xref target="err_OPENMODE" /></c>

      <c>NFS4ERR_OP_ILLEGAL</c>
      <c>10044</c>
      <c><xref target="err_OP_ILLEGAL" /></c>

      <c>NFS4ERR_PERM</c>
      <c>1</c>
      <c><xref target="err_PERM" /></c>

      <c>NFS4ERR_RECLAIM_BAD</c>
      <c>10034</c>
      <c><xref target="err_RECLAIM_BAD" /></c>

      <c>NFS4ERR_RECLAIM_CONFLICT</c>
      <c>10035</c>
      <c><xref target="err_RECLAIM_CONFLICT" /></c>

      <c>NFS4ERR_RESOURCE</c>
      <c>10018</c>
      <c><xref target="err_RESOURCE" /></c>

      <c>NFS4ERR_RESTOREFH</c>
      <c>10030</c>
      <c><xref target="err_RESTOREFH" /></c>

      <c>NFS4ERR_ROFS</c>
      <c>30</c>
      <c><xref target="err_ROFS" /></c>

      <c>NFS4ERR_SAME</c>
      <c>10009</c>
      <c><xref target="err_SAME" /></c>

      <c>NFS4ERR_SERVERFAULT</c>
      <c>10006</c>
      <c><xref target="err_SERVERFAULT" /></c>

      <c>NFS4ERR_SHARE_DENIED</c>
      <c>10015</c>
      <c><xref target="err_SHARE_DENIED" /></c>

      <c>NFS4ERR_STALE</c>
      <c>70</c>
      <c><xref target="err_STALE" /></c>

      <c>NFS4ERR_STALE_CLIENTID</c>
      <c>10022</c>
      <c><xref target="err_STALE_CLIENTID" /></c>

      <c>NFS4ERR_STALE_STATEID</c>
      <c>10023</c>
      <c><xref target="err_STALE_STATEID" /></c>

      <c>NFS4ERR_SYMLINK</c>
      <c>10029</c>
      <c><xref target="err_SYMLINK" /></c>

      <c>NFS4ERR_TOOSMALL</c>
      <c>10005</c>
      <c><xref target="err_TOOSMALL" /></c>

      <c>NFS4ERR_WRONGSEC</c>
      <c>10016</c>
      <c><xref target="err_WRONGSEC" /></c>

      <c>NFS4ERR_XDEV</c>
      <c>18</c>
      <c><xref target="err_XDEV" /></c>

    </texttable>

  <section title="General Errors" anchor="errors_gen">
    <t>
      This section deals with errors that are applicable to a broad
      set of different purposes.
    </t>
    <section title="NFS4ERR_BADXDR (Error Code 10036)"
                    anchor="err_BADXDR">
      <t>
        The arguments for this operation do not match those specified in
        the XDR definition.  This includes situations in which the
        request ends before all the arguments have been seen.  Note
        that this error applies when fixed enumerations (these include
        booleans) have a value within the input stream that is not
        valid for the enum.  A replier may pre-parse all operations for
        a COMPOUND procedure before doing any operation execution
        and return RPC-level XDR errors in that case.
      </t>
    </section>
    <section title="NFS4ERR_BAD_COOKIE (Error Code 10003)"
             anchor="err_BAD_COOKIE">
      <t>
        This error is used for operations that provide a set of
        information indexed by some quantity provided by the client
        or cookie sent by the server for an earlier invocation.
        Where the value cannot be used for its intended purpose,
        this error results.
      </t>
    </section>
    <section title="NFS4ERR_DELAY (Error Code 10008)"
             anchor="err_DELAY">
      <t>
        For any of a number of reasons, the replier could not
        process this operation in what was deemed a reasonable
        time. The client should wait and then try the request
        with a new RPC transaction ID.
      </t>
      <t>
        The following are two examples of what might lead to this situation:
          <list style="symbols">
            <t>
              A server that supports hierarchical storage receives a
              request to process a file that had been migrated.
            </t>
            <t>
             An operation requires a delegation recall to proceed,
             and waiting for this delegation recall makes processing
             this request in a timely fashion impossible.
           </t>
         </list>
       </t>
    </section>
    <section title="NFS4ERR_INVAL (Error Code 22)"
             anchor="err_INVAL">
      <t>
        The arguments for this operation are not valid for some reason, even
        though they do match those specified in the XDR definition for
        the request.
      </t>
    </section>
    <section title="NFS4ERR_NOTSUPP (Error Code 10004)"
             anchor="err_NOTSUPP">
      <t>
        The operation is not supported, either because the operation is
        an OPTIONAL one and is not supported by this server or
        because the operation MUST NOT be implemented in
        the current minor version.
      </t>
    </section>
    <section title="NFS4ERR_SERVERFAULT (Error Code 10006)"
             anchor="err_SERVERFAULT">
      <t>
        An error that does not map to any of the specific legal NFSv4
        protocol error values occurred on the server.  The client
        should translate this into an appropriate error.  UNIX clients
        may choose to translate this to EIO.
     </t>
    </section>
    <section title="NFS4ERR_TOOSMALL (Error Code 10005)"
             anchor="err_TOOSMALL">
      <t>
        This error is used where an operation returns a variable amount
        of data, with a limit specified by the client.  Where the data
        returned cannot be fitted within the limit specified by the
        client, this error results.
      </t>
    </section>
  </section>

  <section title="Filehandle Errors" anchor="errors_fh">
    <t>
      These errors deal with the situation in which the current
      or saved filehandle, or the filehandle passed to PUTFH
      intended to become the current filehandle, is invalid
      in some way.  This includes situations in which the
      filehandle is a valid filehandle in general but is not
      of the appropriate object type for the current operation.
    </t>
    <t>
      Where the error description indicates a problem with the
      current or saved filehandle, it is to be understood that
      filehandles are only checked for the condition if they
      are implicit arguments of the operation in question.
    </t>
    <section title="NFS4ERR_BADHANDLE (Error Code 10001)"
             anchor="err_BADHANDLE">
      <t>
        This error is generated for an illegal NFS filehandle for the
        current server.  The current filehandle failed internal
        consistency checks.  Once accepted as valid (by PUTFH), no
        subsequent status change can cause the filehandle to
        generate this error.
      </t>
    </section>
    <section title="NFS4ERR_FHEXPIRED (Error Code 10014)"
             anchor="err_FHEXPIRED">
      <t>
        A current or saved filehandle that is an argument to the
        current operation is volatile and has expired at the server.
      </t>
    </section>
   <section title="NFS4ERR_ISDIR (Error Code 21)"
             anchor="err_ISDIR">
      <t>
        The current or saved filehandle designates a directory
        when the current operation does not allow a directory to
        be accepted as the target of this operation.
      </t>
    </section>
    <section title="NFS4ERR_MOVED (Error Code 10019)"
             anchor="err_MOVED">
      <t>
        The file system that contains the current filehandle object
        is not present at the server.  It may have been relocated or
        migrated to another server, or may have never been present.
        The client may obtain the new file system location by obtaining
        the "fs_locations" attribute for the current filehandle.
        For further discussion, refer to <xref target="sec:mars" />.
      </t>
    </section>
    <section title="NFS4ERR_NOFILEHANDLE (Error Code 10020)"
             anchor="err_NOFILEHANDLE">
      <t>
        The logical current or saved filehandle value is required by
        the current operation and is not set.
        This may be a result of a malformed COMPOUND
        operation (i.e., no PUTFH or PUTROOTFH before an operation that
        requires that the current filehandle be set).
      </t>
    </section>
    <section title="NFS4ERR_NOTDIR (Error Code 20)"
             anchor="err_NOTDIR">
      <t>
        The current (or saved) filehandle designates an object that
        is not a directory for an operation in which a directory is
        required.
      </t>
    </section>
    <section title="NFS4ERR_STALE (Error Code 70)"
             anchor="err_STALE">
      <t>
        The current or saved filehandle value designating an argument
        to the current operation is invalid.
        The file system object referred to by that filehandle no longer
        exists, or access to it has been revoked.
      </t>
    </section>
    <section title="NFS4ERR_SYMLINK (Error Code 10029)"
             anchor="err_SYMLINK">
      <t>
        The current filehandle designates a symbolic link when the
        current operation does not allow a symbolic link as the
        target.
      </t>
    </section>
  </section>

  <section title="Compound Structure Errors" anchor="errors_comp">
    <t>
      This section deals with errors that relate to the overall structure
      of a COMPOUND request (by which we mean to include both
      COMPOUND and CB_COMPOUND), rather than to particular operations.
    </t>
    <t>
      There are a number of basic constraints on the operations that
      may appear in a COMPOUND request.
    </t>
    <section title="NFS_OK (Error Code 0)"
             anchor="err_OK">
      <t>
        NFS_OK indicates that the operation completed successfully,
        in that all of the constituent operations completed without error.
      </t>
    </section>
    <section title="NFS4ERR_MINOR_VERS_MISMATCH (Error Code 10021)"
             anchor="err_MINOR_VERS_MISMATCH">
      <t>
        The minor version specified is not one that the current listener
        supports.  This value is returned in the overall status for the
        COMPOUND procedure but is not associated with a specific
        operation, since the results must specify a result count of zero.
      </t>
    </section>
    <section title="NFS4ERR_OP_ILLEGAL (Error Code 10044)"
             anchor="err_OP_ILLEGAL">
      <t>
        The operation code is not a valid one for the current
        COMPOUND procedure.  The opcode
        in the result stream matched with this error is the
        ILLEGAL value, although the value that appears in the
        request stream may be different.  Where an illegal
        value appears and the replier pre-parses all operations for
        a COMPOUND procedure before doing any operation execution,
        an RPC-level XDR error may be returned in this case.
      </t>
    </section>
    <section title="NFS4ERR_RESOURCE (Error Code 10018)"
             anchor="err_RESOURCE">
      <t>
        For the processing of the COMPOUND procedure, the server may
        exhaust available resources and cannot continue processing
        operations within the COMPOUND procedure.  This error will
        be returned from the server in those instances of resource
        exhaustion related to the processing of the COMPOUND procedure.
      </t>
    </section>
  </section>

  <section title="File System Errors" anchor="errors_fs">
    <t>
      These errors describe situations that occurred in the underlying
      file system implementation rather than in the protocol or any
      NFSv4.x feature.
    </t>
    <section title="NFS4ERR_BADTYPE (Error Code 10007)"
             anchor="err_BADTYPE">
      <t>
        An attempt was made to create an object with an inappropriate
        type specified to CREATE.  This may be because the type
        is undefined; because it is a type not supported by the
        server; or because it is a type for which create is not
        intended, such as a regular file or named attribute, for
        which OPEN is used to do the file creation.
      </t>
    </section>
    <section title="NFS4ERR_DQUOT (Error Code 69)"
             anchor="err_DQUOT">
      <t>
        The resource (quota) hard limit has been exceeded.
        The user's resource limit on the server has been exceeded.
      </t>
    </section>
    <section title="NFS4ERR_EXIST (Error Code 17)"
             anchor="err_EXIST">
      <t>
        A file system object of the specified target name (when creating,
        renaming, or linking) already exists.
      </t>
    </section>
    <section title="NFS4ERR_FBIG (Error Code 27)"
             anchor="err_FBIG">
      <t>
        The file system object is too large. The operation would have caused a
        file system object to grow beyond the server's limit.
      </t>
    </section>
    <section title="NFS4ERR_FILE_OPEN (Error Code 10046)"
             anchor="err_FILE_OPEN">
      <t>
        The operation is not allowed because a
        file system object involved in the operation is currently open.
        Servers may, but are not required to, disallow linking to,
        removing, or renaming open file system objects.
      </t>
    </section>
    <section title="NFS4ERR_IO (Error Code 5)"
             anchor="err_IO">
      <t>
        This indicates that an I/O error occurred for which the
        file system was unable to provide recovery.
      </t>
    </section>
    <section title="NFS4ERR_MLINK (Error Code 31)"
             anchor="err_MLINK">
      <t>
        The request would have caused the server's limit for the
        number of hard links a file system object may have to be exceeded.
      </t>
    </section>
    <section title="NFS4ERR_NOENT (Error Code 2)"
             anchor="err_NOENT">
      <t>
         This indicates no such file or directory. The file system object referenced by the name
         specified does not exist.
      </t>
    </section>
    <section title="NFS4ERR_NOSPC (Error Code 28)"
             anchor="err_NOSPC">
      <t>
        This indicates no space left on the device. The operation would have
        caused the server's file system to exceed its limit.
      </t>
    </section>
    <section title="NFS4ERR_NOTEMPTY (Error Code 66)"
             anchor="err_NOTEMPTY">
      <t>
         An attempt was made to remove a directory that was not empty.
      </t>
    </section>
    <section title="NFS4ERR_NXIO (Error Code 6)"
             anchor="err_NXIO">
      <t>
        This indicates an I/O error. There is no such device or address.
      </t>
    </section>
    <section title="NFS4ERR_RESTOREFH (Error Code 10030)"
             anchor="err_RESTOREFH">
      <t>
        The RESTOREFH operation does not have a saved filehandle
        (identified by SAVEFH) to operate upon.
      </t>
    </section>
    <section title="NFS4ERR_ROFS (Error Code 30)"
             anchor="err_ROFS">
      <t>
         This indicates a read-only file system. A modifying operation was
         attempted on a read-only file system.
      </t>
    </section>
    <section title="NFS4ERR_XDEV (Error Code 18)"
             anchor="err_XDEV">
      <t>
        This indicates an attempt to do an operation, such as linking,
        that inappropriately crosses a boundary.  For example, this
        may be due to a boundary between:
        <list style="symbols">
          <t>
            File systems (where the fsids are different).
          </t>
          <t>
            Different named attribute directories, or
            between a named attribute directory and an ordinary
            directory.
          </t>
          <t>
            Regions of a file system that the file system
            implementation treats as separate (for example, for space
            accounting purposes), and where cross-connection between
            the regions is not allowed.
          </t>
        </list>
      </t>
    </section>
  </section>

  <section title="State Management Errors" anchor="errors_state_mgt">
    <t>
      These errors indicate problems with the stateid (or one of
      the stateids) passed to a given operation.  This includes
      situations in which the stateid is invalid, as well as
      situations in which the stateid is valid but designates
      revoked locking state.  Depending on the operation, the
      stateid, when valid, may designate opens, byte-range locks,
      or file delegations.
    </t>
    <section title="NFS4ERR_ADMIN_REVOKED (Error Code 10047)"
             anchor="err_ADMIN_REVOKED">
      <t>
        A stateid designates locking state of any type that has been revoked
        due to administrative interaction, possibly while the lease is valid,
        or because a delegation was revoked because of failure to return it,
        while the lease was valid.
      </t>
    </section>
    <section title="NFS4ERR_BAD_STATEID (Error Code 10025)"
             anchor="err_BAD_STATEID">
      <t>
        A stateid generated by the current server instance was used that
        either:

        <list style='symbols'>
          <t>
            Does not designate any locking state (either current or superseded)
            for a current (state-owner, file) pair.
          </t>

          <t>
            Designates locking state that was freed after lease expiration but
            without any lease cancellation, as may happen in the handling of
            "courtesy locks".
          </t>
        </list>
      </t>
    </section>
    <section title="NFS4ERR_EXPIRED (Error Code 10011)"
             anchor="err_EXPIRED">
      <t>
        A stateid or clientid designates locking state of any type that
        has been revoked or released due to cancellation of the client's
        lease, either immediately upon lease expiration, or following a later
        request for a conflicting lock.
      </t>
    </section>
    <section title="NFS4ERR_LEASE_MOVED (Error Code 10031)"
             anchor="err_LEASE_MOVED">
      <t>
        A lease being renewed is associated with a file system
        that has been migrated to a new server.
      </t>
    </section>
    <section title="NFS4ERR_OLD_STATEID (Error Code 10024)"
             anchor="err_OLD_STATEID">
      <t>
        A stateid is provided with a seqid value that is not the most
        current.
      </t>
    </section>
    <section title="NFS4ERR_STALE_STATEID (Error Code 10023)"
             anchor="err_STALE_STATEID">
      <t>
        A stateid generated by an earlier server instance was
        used.
      </t>
    </section>
  </section>

  <section title="Security Errors" anchor="errors_sec">
    <t>
      These are the various permission-related errors in NFSv4.
    </t>
    <section title="NFS4ERR_ACCESS (Error Code 13)"
             anchor="err_ACCESS">
      <t>
        This indicates permission denied. The caller does
        not have the correct permission to perform
        the requested operation. Contrast this with
        NFS4ERR_PERM (<xref target="err_PERM" />), which
        restricts itself to owner or privileged user
        permission failures.
      </t>
    </section>
    <section title="NFS4ERR_PERM (Error Code 1)"
             anchor="err_PERM">
      <t>
        This indicates that the requester is not the owner. The
        operation was not allowed because the caller is neither a
        privileged user (root) nor the owner of the target of the
        operation.
      </t>
    </section>
    <section title="NFS4ERR_WRONGSEC (Error Code 10016)"
             anchor="err_WRONGSEC">
      <t>
        This indicates that the security mechanism being used by the
        client for the operation does not match the server's security
        policy.  The client should change the security mechanism being
        used and re-send the operation.  SECINFO can be used
        to determine the appropriate mechanism.
      </t>
    </section>
  </section>

  <section title="Name Errors" anchor="errors_name">
    <t>
      Names in NFSv4 are UTF-8 strings.  When the strings are not
      of length zero, the error NFS4ERR_INVAL results.  When
      they are not valid UTF&nbhy;8, the error NFS4ERR_INVAL also results,
      but servers may accommodate file systems with different
      character formats and not return this error.  Besides
      this, there are a number of other errors
      to indicate specific problems with names.
    </t>
    <section title="NFS4ERR_BADCHAR (Error Code 10040)"
             anchor="err_BADCHAR">
      <t>
        A UTF-8 string contains a character that is not supported
        by the server in the context in which it is being used.
      </t>
    </section>
    <section title="NFS4ERR_BADNAME (Error Code 10041)"
             anchor="err_BADNAME">
      <t>
         A name string in a request consisted of valid UTF-8
         characters supported by the server, but the name is not
         supported by the server as a valid name for current operation.
         An example might be creating a file or directory named ".."
         on a server whose file system uses that name for links to
         parent directories.
      </t>
      <t>
         This error should not be returned due to a normalization issue
         in a string.  When a file system keeps names in a particular
         normalization form, it is the server's responsibility to
         do the appropriate normalization, rather than rejecting
         the name.
      </t>
    </section>
    <section title="NFS4ERR_NAMETOOLONG (Error Code 63)"
             anchor="err_NAMETOOLONG">
      <t>
         This is returned when the filename in an operation exceeds the
         server's implementation limit.
      </t>
    </section>
  </section>

  <section title="Locking Errors" anchor="errors_locking">
    <t>
      This section deals with errors related to locking -- both 
      share reservations and byte-range locking.  It does not deal
      with errors specific to the process of reclaiming locks.  Those
      are dealt with in the next section.
    </t>
    <section title="NFS4ERR_BAD_RANGE (Error Code 10042)"
             anchor="err_BAD_RANGE">
      <t>
        The range for a LOCK, LOCKT, or LOCKU operation is not
        appropriate to the allowable range of offsets for the
        server.  For example, this error results when a server
        that only supports 32-bit ranges receives a range that
        cannot be handled by that server.  (See
        <xref target="OP_LOCK_DESCRIPTION" />.)

      </t>
    </section>
    <section title="NFS4ERR_BAD_SEQID (Error Code 10026)"
             anchor="err_BAD_SEQID">
      <t>
        The sequence number (seqid) in a locking request is neither the
        next expected number nor the last number processed.
      </t>
    </section>
    <section title="NFS4ERR_DEADLOCK (Error Code 10045)"
             anchor="err_DEADLOCK">
      <t>
        The server has been able to determine a file locking
        deadlock condition for a blocking lock request.
      </t>
    </section>
    <section title="NFS4ERR_DENIED (Error Code 10010)"
             anchor="err_DENIED">
      <t>
        An attempt to lock a file is denied.  Since this may be a
        temporary condition, the client is encouraged to re-send the lock
        request until the lock is accepted.  See
        <xref target="sec:blocklock" /> for a discussion of the re&nbhy;send.
      </t>
    </section>
    <section title="NFS4ERR_LOCKED (Error Code 10012)"
             anchor="err_LOCKED">
      <t>
        A READ or WRITE operation was attempted on a file where there
        was a conflict between the I/O and an existing lock:
        <list style="symbols">
          <t>
            There is a share reservation inconsistent with the I/O
            being done.
          </t>
          <t>
            The range to be read or written intersects an existing
            mandatory byte-range lock.
          </t>
        </list>
      </t>
    </section>
    <section title="NFS4ERR_LOCKS_HELD (Error Code 10037)"
             anchor="err_LOCKS_HELD">
      <t>
        An operation was prevented by the unexpected presence of locks.
      </t>
    </section>
    <section title="NFS4ERR_LOCK_NOTSUPP (Error Code 10043)"
             anchor="err_LOCK_NOTSUPP">
      <t>
        A locking request was attempted that would require the upgrade
        or downgrade of a lock range already held by the owner when the
        server does not support atomic upgrade or downgrade of locks.
      </t>
    </section>
    <section title="NFS4ERR_LOCK_RANGE (Error Code 10028)"
             anchor="err_LOCK_RANGE">
      <t>
        A lock request is operating on a range that partially overlaps a
        currently held lock for the current lock-owner and does not precisely
        match a single such lock, where the server does not support this type
        of request and thus does not implement POSIX locking semantics
        <xref target="fcntl" />. See
        Sections <xref target="OP_LOCK_IMPLEMENTATION" format="counter"/>,
        <xref target="OP_LOCKT_IMPLEMENTATION" format="counter"/>, and
        <xref target="OP_LOCKU_IMPLEMENTATION" format="counter"/> for a
        discussion of how this applies to LOCK, LOCKT, and LOCKU,
        respectively.
      </t>
    </section>
    <section title="NFS4ERR_OPENMODE (Error Code 10038)"
             anchor="err_OPENMODE">
      <t>
        The client attempted a READ, WRITE, LOCK, or other operation
        not sanctioned by the stateid passed (e.g., writing to a file
        opened only for read).
      </t>
    </section>

    <section title="NFS4ERR_SHARE_DENIED (Error Code 10015)"
             anchor="err_SHARE_DENIED">
      <t>
        An attempt to OPEN a file with a share reservation has failed because
        of a share conflict.
      </t>
    </section>
  </section>

  <section title="Reclaim Errors" anchor="errors_reclaim">
    <t>
      These errors relate to the process of reclaiming locks after a
      server restart.
    </t>
    <section title="NFS4ERR_GRACE (Error Code 10013)"
             anchor="err_GRACE">
      <t>
        The server is in its recovery or grace period, which should
        at least match the lease period of the server.  A locking
        request other than a reclaim could not be granted during
        that period.
      </t>
    </section>
    <section title="NFS4ERR_NO_GRACE (Error Code 10033)"
             anchor="err_NO_GRACE">
      <t>
        The server cannot guarantee that it has not granted state to
        another client that may conflict with this client's state.
        No further reclaims from this client will succeed.
      </t>
    </section>
    <section title="NFS4ERR_RECLAIM_BAD (Error Code 10034)"
             anchor="err_RECLAIM_BAD">
      <t>
        The server cannot guarantee that it has not granted state to
        another client that may conflict with the requested state.
        However, this applies only to the state requested in this call;
        further reclaims may succeed.
      </t>
      <t>
        Unlike NFS4ERR_RECLAIM_CONFLICT, this can occur between
        correctly functioning clients and servers: the "edge condition"
        scenarios described in <xref target="ss:fl:edges" /> leave only the
        server knowing whether the client's locks are still valid, and
        NFS4ERR_RECLAIM_BAD is the server's way of informing the client
        that they are not.
      </t>
    </section>
    <section title="NFS4ERR_RECLAIM_CONFLICT (Error Code 10035)"
             anchor="err_RECLAIM_CONFLICT">
      <t>
        The reclaim attempted by the client conflicts with a lock
        already held by another client.  Unlike NFS4ERR_RECLAIM_BAD,
        this can only occur if one of the clients misbehaved.
      </t>
    </section>
  </section>

  <section title="Client Management Errors" anchor="errors_client_mgt">
    <t>
      This section deals with errors associated with requests used
      to create and manage client IDs.
    </t>
    <section title="NFS4ERR_CLID_INUSE (Error Code 10017)"
             anchor="err_CLID_INUSE">
      <t>
        The SETCLIENTID operation has found that a clientid is
        already in use by another client.
      </t>
    </section>
    <section title="NFS4ERR_STALE_CLIENTID (Error Code 10022)"
             anchor="err_STALE_CLIENTID">
      <t>
        A client ID not recognized by the server was used in a locking
        or SETCLIENTID_CONFIRM request.
      </t>
    </section>
  </section>

  <section title="Attribute Handling Errors" anchor="errors_attr">
    <t>
      This section deals with errors specific to attribute handling
      within NFSv4.
    </t>
    <section title="NFS4ERR_ATTRNOTSUPP (Error Code 10032)"
             anchor="err_ATTRNOTSUPP">
      <t>
        An attribute specified is not supported by the server.  This
        error MUST NOT be returned by the GETATTR operation.
      </t>
    </section>
    <section title="NFS4ERR_BADOWNER (Error Code 10039)"
             anchor="err_BADOWNER">
      <t>
        This error is returned when an owner or owner_group attribute value
        or the who field of an ace within an ACL attribute value cannot
        be translated to a local representation.
      </t>
    </section>
    <section title="NFS4ERR_NOT_SAME (Error Code 10027)"
             anchor="err_NOT_SAME">
      <t>
        This error is returned by the VERIFY operation to signify
        that the attributes compared were not the same as those provided
        in the client's request.
      </t>
    </section>
    <section title="NFS4ERR_SAME (Error Code 10009)"
             anchor="err_SAME">
      <t>
        This error is returned by the NVERIFY operation to signify
        that the attributes compared were the same as those provided
        in the client's request.
      </t>
    </section>
  </section>

  <section title="Miscellaneous Errors" anchor="errors_misc">
    <section title="NFS4ERR_CB_PATH_DOWN (Error Code 10048)"
             anchor="err_CB_PATH_DOWN">
      <t>
        There is a problem contacting the client via the callback path.
      </t>
    </section>
  </section>
</section>

<section title="Operations and Their Valid Errors">
  <t>
    This section contains a table that gives the valid error returns
    for each protocol operation.  The error code NFS4_OK (indicating
    no error) is not listed but should be understood to be returnable
    by all operations except ILLEGAL.
  </t>
  <texttable anchor='op_error_returns' title="Valid Error Returns for Each
   Protocol Operation">
    <ttcol align='left'>Operation</ttcol>
    <ttcol align='left'>Errors</ttcol>
    <c>ACCESS</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_INVAL,
      NFS4ERR_IO,
      NFS4ERR_MOVED,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_RESOURCE,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE
    </c>

    <c />
    <c />

    <c>CLOSE</c>
    <c>
      NFS4ERR_ADMIN_REVOKED,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BAD_SEQID,
      NFS4ERR_BAD_STATEID,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_EXPIRED,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_INVAL,
      NFS4ERR_ISDIR,
      NFS4ERR_LEASE_MOVED,
      NFS4ERR_LOCKS_HELD,
      NFS4ERR_MOVED,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_OLD_STATEID,
      NFS4ERR_RESOURCE,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE,
      NFS4ERR_STALE_STATEID
    </c>

    <c />
    <c />

    <c>COMMIT</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_INVAL,
      NFS4ERR_IO,
      NFS4ERR_ISDIR,
      NFS4ERR_MOVED,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_RESOURCE,
      NFS4ERR_ROFS,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE,
      NFS4ERR_SYMLINK
    </c>

    <c />
    <c />

    <c>CREATE</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_ATTRNOTSUPP,
      NFS4ERR_BADCHAR,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BADNAME,
      NFS4ERR_BADOWNER,
      NFS4ERR_BADTYPE,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_DQUOT,
      NFS4ERR_EXIST,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_INVAL,
      NFS4ERR_IO,
      NFS4ERR_MOVED,
      NFS4ERR_NAMETOOLONG,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_NOSPC,
      NFS4ERR_NOTDIR,
      NFS4ERR_PERM,
      NFS4ERR_RESOURCE,
      NFS4ERR_ROFS,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE
    </c>

    <c />
    <c />

    <c>DELEGPURGE</c>
    <c>
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_LEASE_MOVED,
      NFS4ERR_NOTSUPP,
      NFS4ERR_RESOURCE,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE_CLIENTID
    </c>

    <c />
    <c />

    <c>DELEGRETURN</c>
    <c>
      NFS4ERR_ADMIN_REVOKED,
      NFS4ERR_BAD_STATEID,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_EXPIRED,
      NFS4ERR_INVAL,
      NFS4ERR_LEASE_MOVED,
      NFS4ERR_MOVED,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_NOTSUPP,
      NFS4ERR_OLD_STATEID,
      NFS4ERR_RESOURCE,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE,
      NFS4ERR_STALE_STATEID
    </c>

    <c />
    <c />

    <c>GETATTR</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_GRACE,
      NFS4ERR_INVAL,
      NFS4ERR_IO,
      NFS4ERR_MOVED,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_RESOURCE,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE
    </c>

    <c />
    <c />

    <c>GETFH</c>
    <c>
      NFS4ERR_BADHANDLE,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_MOVED,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_RESOURCE,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE
    </c>

    <c />
    <c />

    <c>ILLEGAL</c>
    <c>
      NFS4ERR_BADXDR,
      NFS4ERR_OP_ILLEGAL
    </c>

    <c />
    <c />

    <c>LINK</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_BADCHAR,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BADNAME,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_DQUOT,
      NFS4ERR_EXIST,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_FILE_OPEN,
      NFS4ERR_INVAL,
      NFS4ERR_IO,
      NFS4ERR_ISDIR,
      NFS4ERR_MLINK,
      NFS4ERR_MOVED,
      NFS4ERR_NAMETOOLONG,
      NFS4ERR_NOENT,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_NOSPC,
      NFS4ERR_NOTDIR,
      NFS4ERR_NOTSUPP,
      NFS4ERR_RESOURCE,
      NFS4ERR_ROFS,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE,
      NFS4ERR_WRONGSEC,
      NFS4ERR_XDEV
    </c>

    <c />
    <c />

    <c>LOCK</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_ADMIN_REVOKED,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BAD_RANGE,
      NFS4ERR_BAD_SEQID,
      NFS4ERR_BAD_STATEID,
      NFS4ERR_BADXDR,
      NFS4ERR_DEADLOCK,
      NFS4ERR_DELAY,
      NFS4ERR_DENIED,
      NFS4ERR_EXPIRED,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_GRACE,
      NFS4ERR_INVAL,
      NFS4ERR_ISDIR,
      NFS4ERR_LEASE_MOVED,
      NFS4ERR_LOCK_NOTSUPP,
      NFS4ERR_LOCK_RANGE,
      NFS4ERR_MOVED,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_NO_GRACE,
      NFS4ERR_OLD_STATEID,
      NFS4ERR_OPENMODE,
      NFS4ERR_RECLAIM_BAD,
      NFS4ERR_RECLAIM_CONFLICT,
      NFS4ERR_RESOURCE,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE,
      NFS4ERR_STALE_CLIENTID,
      NFS4ERR_STALE_STATEID
    </c>

    <c />
    <c />

    <c>LOCKT</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BAD_RANGE,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_DENIED,
      NFS4ERR_EXPIRED,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_GRACE,
      NFS4ERR_INVAL,
      NFS4ERR_ISDIR,
      NFS4ERR_LEASE_MOVED,
      NFS4ERR_LOCK_RANGE,
      NFS4ERR_MOVED,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_RESOURCE,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE,
      NFS4ERR_STALE_CLIENTID
    </c>

    <c />
    <c />

    <c>LOCKU</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_ADMIN_REVOKED,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BAD_RANGE,
      NFS4ERR_BAD_SEQID,
      NFS4ERR_BAD_STATEID,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_EXPIRED,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_GRACE,
      NFS4ERR_INVAL,
      NFS4ERR_ISDIR,
      NFS4ERR_LEASE_MOVED,
      NFS4ERR_LOCK_RANGE,
      NFS4ERR_MOVED,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_OLD_STATEID,
      NFS4ERR_RESOURCE,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE,
      NFS4ERR_STALE_STATEID
    </c>

    <c />
    <c />

    <c>LOOKUP</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_BADCHAR,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BADNAME,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_INVAL,
      NFS4ERR_IO,
      NFS4ERR_MOVED,
      NFS4ERR_NAMETOOLONG,
      NFS4ERR_NOENT,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_NOTDIR,
      NFS4ERR_RESOURCE,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE,
      NFS4ERR_SYMLINK,
      NFS4ERR_WRONGSEC
    </c>

    <c />
    <c />

    <c>LOOKUPP</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_BADHANDLE,
      NFS4ERR_DELAY,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_IO,
      NFS4ERR_MOVED,
      NFS4ERR_NOENT,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_NOTDIR,
      NFS4ERR_RESOURCE,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE,
      NFS4ERR_SYMLINK,
      NFS4ERR_WRONGSEC
    </c>

    <c />
    <c />

    <c>NVERIFY</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_ATTRNOTSUPP,
      NFS4ERR_BADCHAR,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_GRACE,
      NFS4ERR_INVAL,
      NFS4ERR_IO,
      NFS4ERR_MOVED,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_SAME,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE
    </c>

    <c />
    <c />

    <c>OPEN</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_ADMIN_REVOKED,
      NFS4ERR_ATTRNOTSUPP,
      NFS4ERR_BADCHAR,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BADNAME,
      NFS4ERR_BADOWNER,
      NFS4ERR_BAD_SEQID,
      NFS4ERR_BAD_STATEID,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_DQUOT,
      NFS4ERR_EXIST,
      NFS4ERR_EXPIRED,
      NFS4ERR_FBIG,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_GRACE,
      NFS4ERR_INVAL,
      NFS4ERR_IO,
      NFS4ERR_ISDIR,
      NFS4ERR_MOVED,
      NFS4ERR_NAMETOOLONG,
      NFS4ERR_NOENT,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_NO_GRACE,
      NFS4ERR_NOSPC,
      NFS4ERR_NOTDIR,
      NFS4ERR_NOTSUPP,
      NFS4ERR_OLD_STATEID,
      NFS4ERR_PERM,
      NFS4ERR_RECLAIM_BAD,
      NFS4ERR_RECLAIM_CONFLICT,
      NFS4ERR_RESOURCE,
      NFS4ERR_ROFS,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_SHARE_DENIED,
      NFS4ERR_STALE,
      NFS4ERR_STALE_CLIENTID,
      NFS4ERR_SYMLINK,
      NFS4ERR_WRONGSEC
    </c>

    <c />
    <c />

    <c>OPENATTR</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_DQUOT,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_IO,
      NFS4ERR_MOVED,
      NFS4ERR_NOENT,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_NOSPC,
      NFS4ERR_NOTSUPP,
      NFS4ERR_RESOURCE,
      NFS4ERR_ROFS,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE
    </c>

    <c />
    <c />

    <c>OPEN_CONFIRM</c>
    <c>
      NFS4ERR_ADMIN_REVOKED,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BAD_SEQID,
      NFS4ERR_BAD_STATEID,
      NFS4ERR_BADXDR,
      NFS4ERR_EXPIRED,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_INVAL,
      NFS4ERR_ISDIR,
      NFS4ERR_LEASE_MOVED,
      NFS4ERR_MOVED,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_OLD_STATEID,
      NFS4ERR_RESOURCE,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE,
      NFS4ERR_STALE_STATEID
    </c>

    <c />
    <c />

    <c>OPEN_DOWNGRADE</c>
    <c>
      NFS4ERR_ADMIN_REVOKED,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BAD_SEQID,
      NFS4ERR_BAD_STATEID,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_EXPIRED,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_INVAL,
      NFS4ERR_LEASE_MOVED,
      NFS4ERR_LOCKS_HELD,
      NFS4ERR_MOVED,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_OLD_STATEID,
      NFS4ERR_RESOURCE,
      NFS4ERR_ROFS,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE,
      NFS4ERR_STALE_STATEID
    </c>

    <c />
    <c />

    <c>PUTFH</c>
    <c>
      NFS4ERR_BADHANDLE,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_MOVED,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE,
      NFS4ERR_WRONGSEC
    </c>

    <c />
    <c />

    <c>PUTPUBFH</c>
    <c>
      NFS4ERR_DELAY,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_WRONGSEC
    </c>

    <c />
    <c />

    <c>PUTROOTFH</c>
    <c>
      NFS4ERR_DELAY,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_WRONGSEC
    </c>

    <c />
    <c />

    <c>READ</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_ADMIN_REVOKED,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BAD_STATEID,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_EXPIRED,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_GRACE,
      NFS4ERR_INVAL,
      NFS4ERR_IO,
      NFS4ERR_ISDIR,
      NFS4ERR_LEASE_MOVED,
      NFS4ERR_LOCKED,
      NFS4ERR_MOVED,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_OLD_STATEID,
      NFS4ERR_OPENMODE,
      NFS4ERR_RESOURCE,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE,
      NFS4ERR_STALE_STATEID,
      NFS4ERR_SYMLINK
   </c>

    <c />
    <c />

    <c>READDIR</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_BAD_COOKIE,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_INVAL,
      NFS4ERR_IO,
      NFS4ERR_MOVED,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_NOTDIR,
      NFS4ERR_NOT_SAME,
      NFS4ERR_RESOURCE,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE,
      NFS4ERR_TOOSMALL
    </c>

    <c />
    <c />

    <c>READLINK</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_BADHANDLE,
      NFS4ERR_DELAY,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_INVAL,
      NFS4ERR_IO,
      NFS4ERR_ISDIR,
      NFS4ERR_MOVED,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_NOTSUPP,
      NFS4ERR_RESOURCE,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE
    </c>

    <c />
    <c />

    <c>RELEASE_LOCKOWNER</c>
    <c>
      NFS4ERR_BADXDR,
      NFS4ERR_EXPIRED,
      NFS4ERR_LEASE_MOVED,
      NFS4ERR_LOCKS_HELD,
      NFS4ERR_RESOURCE,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE_CLIENTID
    </c>

    <c />
    <c />

    <c>REMOVE</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_BADCHAR,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BADNAME,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_FILE_OPEN,
      NFS4ERR_GRACE,
      NFS4ERR_INVAL,
      NFS4ERR_IO,
      NFS4ERR_MOVED,
      NFS4ERR_NAMETOOLONG,
      NFS4ERR_NOENT,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_NOTDIR,
      NFS4ERR_NOTEMPTY,
      NFS4ERR_RESOURCE,
      NFS4ERR_ROFS,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE
    </c>

    <c />
    <c />

    <c>RENAME</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_BADCHAR,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BADNAME,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_DQUOT,
      NFS4ERR_EXIST,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_FILE_OPEN,
      NFS4ERR_GRACE,
      NFS4ERR_INVAL,
      NFS4ERR_IO,
      NFS4ERR_MOVED,
      NFS4ERR_NAMETOOLONG,
      NFS4ERR_NOENT,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_NOSPC,
      NFS4ERR_NOTDIR,
      NFS4ERR_NOTEMPTY,
      NFS4ERR_RESOURCE,
      NFS4ERR_ROFS,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE,
      NFS4ERR_WRONGSEC,
      NFS4ERR_XDEV
    </c>

    <c />
    <c />

    <c>RENEW</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_BADXDR,
      NFS4ERR_CB_PATH_DOWN,
      NFS4ERR_EXPIRED,
      NFS4ERR_LEASE_MOVED,
      NFS4ERR_RESOURCE,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE_CLIENTID
    </c>

    <c />
    <c />

    <c>RESTOREFH</c>
    <c>
      NFS4ERR_BADHANDLE,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_MOVED,
      NFS4ERR_RESOURCE,
      NFS4ERR_RESTOREFH,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE,
      NFS4ERR_WRONGSEC
    </c>

    <c />
    <c />

    <c>SAVEFH</c>
    <c>
      NFS4ERR_BADHANDLE,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_MOVED,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_RESOURCE,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE
    </c>

    <c />
    <c />

    <c>SECINFO</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_BADCHAR,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BADNAME,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_INVAL,
      NFS4ERR_MOVED,
      NFS4ERR_NAMETOOLONG,
      NFS4ERR_NOENT,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_NOTDIR,
      NFS4ERR_RESOURCE,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE
    </c>

    <c />
    <c />

    <c>SETATTR</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_ADMIN_REVOKED,
      NFS4ERR_ATTRNOTSUPP,
      NFS4ERR_BADCHAR,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BADOWNER,
      NFS4ERR_BAD_STATEID,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_DQUOT,
      NFS4ERR_EXPIRED,
      NFS4ERR_FBIG,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_GRACE,
      NFS4ERR_INVAL,
      NFS4ERR_IO,
      NFS4ERR_ISDIR,
      NFS4ERR_LEASE_MOVED,
      NFS4ERR_LOCKED,
      NFS4ERR_MOVED,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_NOSPC,
      NFS4ERR_OLD_STATEID,
      NFS4ERR_OPENMODE,
      NFS4ERR_PERM,
      NFS4ERR_RESOURCE,
      NFS4ERR_ROFS,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE,
      NFS4ERR_STALE_STATEID
    </c>

    <c />
    <c />

    <c>SETCLIENTID</c>
    <c>
      NFS4ERR_BADXDR,
      NFS4ERR_CLID_INUSE,
      NFS4ERR_DELAY,
      NFS4ERR_INVAL,
      NFS4ERR_RESOURCE,
      NFS4ERR_SERVERFAULT
    </c>

    <c />
    <c />

    <c>SETCLIENTID_CONFIRM</c>
    <c>
      NFS4ERR_BADXDR,
      NFS4ERR_CLID_INUSE,
      NFS4ERR_DELAY,
      NFS4ERR_RESOURCE,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE_CLIENTID
    </c>

    <c />
    <c />

    <c>VERIFY</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_ATTRNOTSUPP,
      NFS4ERR_BADCHAR,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_GRACE,
      NFS4ERR_INVAL,
      NFS4ERR_IO,
      NFS4ERR_MOVED,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_NOT_SAME,
      NFS4ERR_RESOURCE,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE
    </c>

    <c />
    <c />

    <c>WRITE</c>
    <c>
      NFS4ERR_ACCESS,
      NFS4ERR_ADMIN_REVOKED,
      NFS4ERR_BADHANDLE,
      NFS4ERR_BAD_STATEID,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_DQUOT,
      NFS4ERR_EXPIRED,
      NFS4ERR_FBIG,
      NFS4ERR_FHEXPIRED,
      NFS4ERR_GRACE,
      NFS4ERR_INVAL,
      NFS4ERR_IO,
      NFS4ERR_ISDIR,
      NFS4ERR_LEASE_MOVED,
      NFS4ERR_LOCKED,
      NFS4ERR_MOVED,
      NFS4ERR_NOFILEHANDLE,
      NFS4ERR_NOSPC,
      NFS4ERR_NXIO,
      NFS4ERR_OLD_STATEID,
      NFS4ERR_OPENMODE,
      NFS4ERR_RESOURCE,
      NFS4ERR_ROFS,
      NFS4ERR_SERVERFAULT,
      NFS4ERR_STALE,
      NFS4ERR_STALE_STATEID,
      NFS4ERR_SYMLINK
    </c>

    <c />
    <c />
  </texttable>
</section>

<section title="Callback Operations and Their Valid Errors">
  <t>
    This section contains a table that gives the valid error returns
    for each callback operation.  The error code NFS4_OK (indicating
    no error) is not listed but should be understood to be returnable
    by all callback operations, with the exception of CB_ILLEGAL.
  </t>
  <texttable anchor='cb_op_error_returns' title="Valid Error Returns for Each
   Protocol Callback Operation">
    <ttcol align='left'>Callback Operation</ttcol>
    <ttcol align='left'>Errors</ttcol>
    <c>CB_GETATTR</c>
    <c>
      NFS4ERR_BADHANDLE,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_INVAL,
      NFS4ERR_SERVERFAULT
    </c>

    <c />
    <c />

    <c>CB_ILLEGAL</c>
    <c>
      NFS4ERR_BADXDR,
      NFS4ERR_OP_ILLEGAL
    </c>

    <c />
    <c />

    <c>CB_RECALL</c>
    <c>
      NFS4ERR_BADHANDLE,
      NFS4ERR_BAD_STATEID,
      NFS4ERR_BADXDR,
      NFS4ERR_DELAY,
      NFS4ERR_SERVERFAULT
    </c>

    <c />
    <c />
  </texttable>
</section>

<section title="Errors and the Operations That Use Them">
  <texttable anchor='error_op_returns' title="Errors and the Operations That
    Use Them">
    <ttcol align='left'>Error</ttcol>
    <ttcol align='left'>Operations</ttcol>

    <c>NFS4ERR_ACCESS</c>
    <c>
        ACCESS,
        COMMIT,
        CREATE,
        GETATTR,
        LINK,
        LOCK,
        LOCKT,
        LOCKU,
        LOOKUP,
        LOOKUPP,
        NVERIFY,
        OPEN,
        OPENATTR,
        READ,
        READDIR,
        READLINK,
        REMOVE,
        RENAME,
        RENEW,
        SECINFO,
        SETATTR,
        VERIFY,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_ADMIN_REVOKED</c>
    <c>
        CLOSE,
        DELEGRETURN,
        LOCK,
        LOCKU,
        OPEN,
        OPEN_CONFIRM,
        OPEN_DOWNGRADE,
        READ,
        SETATTR,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_ATTRNOTSUPP</c>
    <c>
        CREATE,
        NVERIFY,
        OPEN,
        SETATTR,
        VERIFY
    </c>
    <c />
    <c />

    <c>NFS4ERR_BADCHAR</c>
    <c>
        CREATE,
        LINK,
        LOOKUP,
        NVERIFY,
        OPEN,
        REMOVE,
        RENAME,
        SECINFO,
        SETATTR,
        VERIFY
    </c>
    <c />
    <c />

    <c>NFS4ERR_BADHANDLE</c>
    <c>
        ACCESS,
        CB_GETATTR,
        CB_RECALL,
        CLOSE,
        COMMIT,
        CREATE,
        GETATTR,
        GETFH,
        LINK,
        LOCK,
        LOCKT,
        LOCKU,
        LOOKUP,
        LOOKUPP,
        NVERIFY,
        OPEN,
        OPENATTR,
        OPEN_CONFIRM,
        OPEN_DOWNGRADE,
        PUTFH,
        READ,
        READDIR,
        READLINK,
        REMOVE,
        RENAME,
        RESTOREFH,
        SAVEFH,
        SECINFO,
        SETATTR,
        VERIFY,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_BADNAME</c>
    <c>
        CREATE,
        LINK,
        LOOKUP,
        OPEN,
        REMOVE,
        RENAME,
        SECINFO
    </c>
    <c />
    <c />

    <c>NFS4ERR_BADOWNER</c>
    <c>
        CREATE,
        OPEN,
        SETATTR
    </c>
    <c />
    <c />

    <c>NFS4ERR_BADTYPE</c>
    <c>
        CREATE
    </c>
    <c />
    <c />

    <c>NFS4ERR_BADXDR</c>
    <c>
        ACCESS,
        CB_GETATTR,
        CB_ILLEGAL,
        CB_RECALL,
        CLOSE,
        COMMIT,
        CREATE,
        DELEGPURGE,
        DELEGRETURN,
        GETATTR,
        ILLEGAL,
        LINK,
        LOCK,
        LOCKT,
        LOCKU,
        LOOKUP,
        NVERIFY,
        OPEN,
        OPENATTR,
        OPEN_CONFIRM,
        OPEN_DOWNGRADE,
        PUTFH,
        READ,
        READDIR,
        RELEASE_LOCKOWNER,
        REMOVE,
        RENAME,
        RENEW,
        SECINFO,
        SETATTR,
        SETCLIENTID,
        SETCLIENTID_CONFIRM,
        VERIFY,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_BAD_COOKIE</c>
    <c>
        READDIR
    </c>
    <c />
    <c />

    <c>NFS4ERR_BAD_RANGE</c>
    <c>
        LOCK,
        LOCKT,
        LOCKU
    </c>
    <c />
    <c />

    <c>NFS4ERR_BAD_SEQID</c>
    <c>
        CLOSE,
        LOCK,
        LOCKU,
        OPEN,
        OPEN_CONFIRM,
        OPEN_DOWNGRADE
    </c>
    <c />
    <c />

    <c>NFS4ERR_BAD_STATEID</c>
    <c>
        CB_RECALL,
        CLOSE,
        DELEGRETURN,
        LOCK,
        LOCKU,
        OPEN,
        OPEN_CONFIRM,
        OPEN_DOWNGRADE,
        READ,
        SETATTR,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_CB_PATH_DOWN</c>
    <c>
        RENEW
    </c>
    <c />
    <c />

    <c>NFS4ERR_CLID_INUSE</c>
    <c>
        SETCLIENTID,
        SETCLIENTID_CONFIRM
    </c>
    <c />
    <c />

    <c>NFS4ERR_DEADLOCK</c>
    <c>
        LOCK
    </c>
    <c />
    <c />

    <c>NFS4ERR_DELAY</c>
    <c>
        ACCESS,
        CB_GETATTR,
        CB_RECALL,
        CLOSE,
        COMMIT,
        CREATE,
        DELEGPURGE,
        DELEGRETURN,
        GETATTR,
        LINK,
        LOCK,
        LOCKT,
        LOCKU,
        LOOKUP,
        LOOKUPP,
        NVERIFY,
        OPEN,
        OPENATTR,
        OPEN_DOWNGRADE,
        PUTFH,
        PUTPUBFH,
        PUTROOTFH,
        READ,
        READDIR,
        READLINK,
        REMOVE,
        RENAME,
        SECINFO,
        SETATTR,
        SETCLIENTID,
        SETCLIENTID_CONFIRM,
        VERIFY,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_DENIED</c>
    <c>
        LOCK,
        LOCKT
    </c>
    <c />
    <c />

    <c>NFS4ERR_DQUOT</c>
    <c>
        CREATE,
        LINK,
        OPEN,
        OPENATTR,
        RENAME,
        SETATTR,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_EXIST</c>
    <c>
        CREATE,
        LINK,
        OPEN,
        RENAME
    </c>
    <c />
    <c />

    <c>NFS4ERR_EXPIRED</c>
    <c>
        CLOSE,
        DELEGRETURN,
        LOCK,
        LOCKT,
        LOCKU,
        OPEN,
        OPEN_CONFIRM,
        OPEN_DOWNGRADE,
        READ,
        RELEASE_LOCKOWNER,
        RENEW,
        SETATTR,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_FBIG</c>
    <c>
        OPEN,
        SETATTR,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_FHEXPIRED</c>
    <c>
        ACCESS,
        CLOSE,
        COMMIT,
        CREATE,
        GETATTR,
        GETFH,
        LINK,
        LOCK,
        LOCKT,
        LOCKU,
        LOOKUP,
        LOOKUPP,
        NVERIFY,
        OPEN,
        OPENATTR,
        OPEN_CONFIRM,
        OPEN_DOWNGRADE,
        PUTFH,
        READ,
        READDIR,
        READLINK,
        REMOVE,
        RENAME,
        RESTOREFH,
        SAVEFH,
        SECINFO,
        SETATTR,
        VERIFY,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_FILE_OPEN</c>
    <c>
        LINK,
        REMOVE,
        RENAME
    </c>
    <c />
    <c />

    <c>NFS4ERR_GRACE</c>
    <c>
        GETATTR,
        LOCK,
        LOCKT,
        LOCKU,
        NVERIFY,
        OPEN,
        READ,
        REMOVE,
        RENAME,
        SETATTR,
        VERIFY,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_INVAL</c>
    <c>
        ACCESS,
        CB_GETATTR,
        CLOSE,
        COMMIT,
        CREATE,
        DELEGRETURN,
        GETATTR,
        LINK,
        LOCK,
        LOCKT,
        LOCKU,
        LOOKUP,
        NVERIFY,
        OPEN,
        OPEN_CONFIRM,
        OPEN_DOWNGRADE,
        READ,
        READDIR,
        READLINK,
        REMOVE,
        RENAME,
        SECINFO,
        SETATTR,
        SETCLIENTID,
        VERIFY,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_IO</c>
    <c>
        ACCESS,
        COMMIT,
        CREATE,
        GETATTR,
        LINK,
        LOOKUP,
        LOOKUPP,
        NVERIFY,
        OPEN,
        OPENATTR,
        READ,
        READDIR,
        READLINK,
        REMOVE,
        RENAME,
        SETATTR,
        VERIFY,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_ISDIR</c>
    <c>
        CLOSE,
        COMMIT,
        LINK,
        LOCK,
        LOCKT,
        LOCKU,
        OPEN,
        OPEN_CONFIRM,
        READ,
        READLINK,
        SETATTR,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_LEASE_MOVED</c>
    <c>
        CLOSE,
        DELEGPURGE,
        DELEGRETURN,
        LOCK,
        LOCKT,
        LOCKU,
        OPEN_CONFIRM,
        OPEN_DOWNGRADE,
        READ,
        RELEASE_LOCKOWNER,
        RENEW,
        SETATTR,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_LOCKED</c>
    <c>
        READ,
        SETATTR,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_LOCKS_HELD</c>
    <c>
        CLOSE,
        OPEN_DOWNGRADE,
        RELEASE_LOCKOWNER
    </c>
    <c />
    <c />

    <c>NFS4ERR_LOCK_NOTSUPP</c>
    <c>
        LOCK
    </c>
    <c />
    <c />

    <c>NFS4ERR_LOCK_RANGE</c>
    <c>
        LOCK,
        LOCKT,
        LOCKU
    </c>
    <c />
    <c />

    <c>NFS4ERR_MLINK</c>
    <c>
        LINK
    </c>
    <c />
    <c />

    <c>NFS4ERR_MOVED</c>
    <c>
        ACCESS,
        CLOSE,
        COMMIT,
        CREATE,
        DELEGRETURN,
        GETATTR,
        GETFH,
        LINK,
        LOCK,
        LOCKT,
        LOCKU,
        LOOKUP,
        LOOKUPP,
        NVERIFY,
        OPEN,
        OPENATTR,
        OPEN_CONFIRM,
        OPEN_DOWNGRADE,
        PUTFH,
        READ,
        READDIR,
        READLINK,
        REMOVE,
        RENAME,
        RESTOREFH,
        SAVEFH,
        SECINFO,
        SETATTR,
        VERIFY,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_NAMETOOLONG</c>
    <c>
        CREATE,
        LINK,
        LOOKUP,
        OPEN,
        REMOVE,
        RENAME,
        SECINFO
    </c>
    <c />
    <c />

    <c>NFS4ERR_NOENT</c>
    <c>
        LINK,
        LOOKUP,
        LOOKUPP,
        OPEN,
        OPENATTR,
        REMOVE,
        RENAME,
        SECINFO
    </c>
    <c />
    <c />

    <c>NFS4ERR_NOFILEHANDLE</c>
    <c>
        ACCESS,
        CLOSE,
        COMMIT,
        CREATE,
        DELEGRETURN,
        GETATTR,
        GETFH,
        LINK,
        LOCK,
        LOCKT,
        LOCKU,
        LOOKUP,
        LOOKUPP,
        NVERIFY,
        OPEN,
        OPENATTR,
        OPEN_CONFIRM,
        OPEN_DOWNGRADE,
        READ,
        READDIR,
        READLINK,
        REMOVE,
        RENAME,
        SAVEFH,
        SECINFO,
        SETATTR,
        VERIFY,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_NOSPC</c>
    <c>
        CREATE,
        LINK,
        OPEN,
        OPENATTR,
        RENAME,
        SETATTR,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_NOTDIR</c>
    <c>
        CREATE,
        LINK,
        LOOKUP,
        LOOKUPP,
        OPEN,
        READDIR,
        REMOVE,
        RENAME,
        SECINFO
    </c>
    <c />
    <c />

    <c>NFS4ERR_NOTEMPTY</c>
    <c>
        REMOVE,
        RENAME
    </c>
    <c />
    <c />

    <c>NFS4ERR_NOTSUPP</c>
    <c>
        DELEGPURGE,
        DELEGRETURN,
        LINK,
        OPEN,
        OPENATTR,
        READLINK
    </c>
    <c />
    <c />

    <c>NFS4ERR_NOT_SAME</c>
    <c>
        READDIR,
        VERIFY
    </c>
    <c />
    <c />

    <c>NFS4ERR_NO_GRACE</c>
    <c>
        LOCK,
        OPEN
    </c>
    <c />
    <c />

    <c>NFS4ERR_NXIO</c>
    <c>
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_OLD_STATEID</c>
    <c>
        CLOSE,
        DELEGRETURN,
        LOCK,
        LOCKU,
        OPEN,
        OPEN_CONFIRM,
        OPEN_DOWNGRADE,
        READ,
        SETATTR,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_OPENMODE</c>
    <c>
        LOCK,
        READ,
        SETATTR,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_OP_ILLEGAL</c>
    <c>
        CB_ILLEGAL,
        ILLEGAL
    </c>
    <c />
    <c />

    <c>NFS4ERR_PERM</c>
    <c>
        CREATE,
        OPEN,
        SETATTR
    </c>
    <c />
    <c />

    <c>NFS4ERR_RECLAIM_BAD</c>
    <c>
        LOCK,
        OPEN
    </c>
    <c />
    <c />

    <c>NFS4ERR_RECLAIM_CONFLICT</c>
    <c>
        LOCK,
        OPEN
    </c>
    <c />
    <c />

    <c>NFS4ERR_RESOURCE</c>
    <c>
        ACCESS,
        CLOSE,
        COMMIT,
        CREATE,
        DELEGPURGE,
        DELEGRETURN,
        GETATTR,
        GETFH,
        LINK,
        LOCK,
        LOCKT,
        LOCKU,
        LOOKUP,
        LOOKUPP,
        OPEN,
        OPENATTR,
        OPEN_CONFIRM,
        OPEN_DOWNGRADE,
        READ,
        READDIR,
        READLINK,
        RELEASE_LOCKOWNER,
        REMOVE,
        RENAME,
        RENEW,
        RESTOREFH,
        SAVEFH,
        SECINFO,
        SETATTR,
        SETCLIENTID,
        SETCLIENTID_CONFIRM,
        VERIFY,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_RESTOREFH</c>
    <c>
        RESTOREFH
    </c>
    <c />
    <c />

    <c>NFS4ERR_ROFS</c>
    <c>
        COMMIT,
        CREATE,
        LINK,
        OPEN,
        OPENATTR,
        OPEN_DOWNGRADE,
        REMOVE,
        RENAME,
        SETATTR,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_SAME</c>
    <c>
        NVERIFY
    </c>
    <c />
    <c />

    <c>NFS4ERR_SERVERFAULT</c>
    <c>
        ACCESS,
        CB_GETATTR,
        CB_RECALL,
        CLOSE,
        COMMIT,
        CREATE,
        DELEGPURGE,
        DELEGRETURN,
        GETATTR,
        GETFH,
        LINK,
        LOCK,
        LOCKT,
        LOCKU,
        LOOKUP,
        LOOKUPP,
        NVERIFY,
        OPEN,
        OPENATTR,
        OPEN_CONFIRM,
        OPEN_DOWNGRADE,
        PUTFH,
        PUTPUBFH,
        PUTROOTFH,
        READ,
        READDIR,
        READLINK,
        RELEASE_LOCKOWNER,
        REMOVE,
        RENAME,
        RENEW,
        RESTOREFH,
        SAVEFH,
        SECINFO,
        SETATTR,
        SETCLIENTID,
        SETCLIENTID_CONFIRM,
        VERIFY,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_SHARE_DENIED</c>
    <c>
        OPEN
    </c>
    <c />
    <c />

    <c>NFS4ERR_STALE</c>
    <c>
        ACCESS,
        CLOSE,
        COMMIT,
        CREATE,
        DELEGRETURN,
        GETATTR,
        GETFH,
        LINK,
        LOCK,
        LOCKT,
        LOCKU,
        LOOKUP,
        LOOKUPP,
        NVERIFY,
        OPEN,
        OPENATTR,
        OPEN_CONFIRM,
        OPEN_DOWNGRADE,
        PUTFH,
        READ,
        READDIR,
        READLINK,
        REMOVE,
        RENAME,
        RESTOREFH,
        SAVEFH,
        SECINFO,
        SETATTR,
        VERIFY,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_STALE_CLIENTID</c>
    <c>
        DELEGPURGE,
        LOCK,
        LOCKT,
        OPEN,
        RELEASE_LOCKOWNER,
        RENEW,
        SETCLIENTID_CONFIRM
    </c>
    <c />
    <c />

    <c>NFS4ERR_STALE_STATEID</c>
    <c>
        CLOSE,
        DELEGRETURN,
        LOCK,
        LOCKU,
        OPEN_CONFIRM,
        OPEN_DOWNGRADE,
        READ,
        SETATTR,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_SYMLINK</c>
    <c>
        COMMIT,
        LOOKUP,
        LOOKUPP,
        OPEN,
        READ,
        WRITE
    </c>
    <c />
    <c />

    <c>NFS4ERR_TOOSMALL</c>
    <c>
        READDIR
    </c>
    <c />
    <c />

    <c>NFS4ERR_WRONGSEC</c>
    <c>
        LINK,
        LOOKUP,
        LOOKUPP,
        OPEN,
        PUTFH,
        PUTPUBFH,
        PUTROOTFH,
        RENAME,
        RESTOREFH
    </c>
    <c />
    <c />

    <c>NFS4ERR_XDEV</c>
    <c>
        LINK,
        RENAME
    </c>
    <c />
    <c />

  </texttable>
</section>

</section>

<section anchor="sec:requests" title="NFSv4 Requests">
  <t>
    For the NFSv4 RPC program, there are two traditional RPC
    procedures: NULL and COMPOUND.  All other functionality is defined as
    a set of operations, and these operations are defined in normal
    XDR/RPC syntax and semantics.  However, these operations are
    encapsulated within the COMPOUND procedure.  This requires that the
    client combine one or more of the NFSv4 operations into a
    single request.
  </t>

  <t>
    The NFS4_CALLBACK program is used to provide server-to-client
    signaling and is constructed in a fashion similar to the
    NFSv4 program.  The procedures CB_NULL and CB_COMPOUND are defined in
    the same way as NULL and COMPOUND are within the NFS program.  The
    CB_COMPOUND request also encapsulates the remaining operations of the
    NFS4_CALLBACK program.  There is no predefined RPC program number for
    the NFS4_CALLBACK program.  It is up to the client to specify a
    program number in the "transient" program range.  The program and
    port numbers of the NFS4_CALLBACK program are provided by the client
    as part of the SETCLIENTID/SETCLIENTID_CONFIRM sequence. The program
    and port can be changed by another SETCLIENTID/SETCLIENTID_CONFIRM
    sequence, and it is possible to use the sequence to change them
    within a client incarnation without removing relevant leased client
    state.
  </t>

  <section title="COMPOUND Procedure">
    <t>
      The COMPOUND procedure provides the opportunity for better
      performance within high-latency networks.  The client can avoid
      cumulative latency of multiple RPCs by combining multiple dependent
      operations into a single COMPOUND procedure.  A COMPOUND operation
      may provide for protocol simplification by allowing the client to
      combine basic procedures into a single request that is customized for
      the client's environment.
    </t>

    <t>
      The CB_COMPOUND procedure precisely parallels the features of
      COMPOUND as described above.
    </t>

    <t>
      The basic structure of the COMPOUND procedure is:

      <figure>
        <artwork>
+-----+--------------+--------+-----------+-----------+-----------+--
| tag | minorversion | numops | op + args | op + args | op + args |
+-----+--------------+--------+-----------+-----------+-----------+--
        </artwork>
      </figure>
    </t>

    <t>
      and the reply's structure is:

      <figure>
        <artwork>
  +------------+-----+--------+-----------------------+--
  |last status | tag | numres | status + op + results |
  +------------+-----+--------+-----------------------+--
        </artwork>
      </figure>
    </t>

    <t>
      The numops and numres fields, used in the depiction above, represent
      the count for the counted array encoding used to signify the number of
      arguments or results encoded in the request and response.  As per the
      XDR encoding, these counts must match exactly the number of operation
      arguments or results encoded.
    </t>
  </section>

  <section title="Evaluation of a COMPOUND Request">
    <t>
      The server will process the COMPOUND procedure by evaluating each of
      the operations within the COMPOUND procedure in order.  Each
      component operation consists of a 32-bit operation code, followed by
      the argument of length determined by the type of operation. The
      results of each operation are encoded in sequence into a reply
      buffer.  The results of each operation are preceded by the opcode and
      a status code (normally zero).  If an operation results in a non-zero
      status code, the status will be encoded, evaluation of the
      COMPOUND sequence will halt, and the reply will be returned.  Note
      that evaluation stops even in the event of "non-error" conditions
      such as NFS4ERR_SAME.
    </t>

    <t>
      There are no atomicity requirements for the operations contained
      within the COMPOUND procedure.  The operations being evaluated as
      part of a COMPOUND request may be evaluated simultaneously with other
      COMPOUND requests that the server receives.
    </t>

    <t>
      A COMPOUND is not a transaction, and it is the client's
      responsibility to recover from any partially completed
      COMPOUND procedure.  These may occur at any point due to errors such as
      NFS4ERR_RESOURCE and NFS4ERR_DELAY.  Note that these errors can occur
      in an otherwise valid operation string.  Further, a server reboot that
      occurs in the middle of processing a COMPOUND procedure may leave the
      client with the difficult task of determining how far COMPOUND
      processing has proceeded.  Therefore, the client should avoid overly
      complex COMPOUND procedures in the event of the failure of an
      operation within the procedure.
    </t>

    <t>
      Each operation assumes a current filehandle and a
      saved filehandle that are available as part of the execution
      context of the COMPOUND request.  Operations may set, change, or
      return the current filehandle.  The saved filehandle is used for
      temporary storage of a filehandle value and as operands for the
      RENAME and LINK operations.
    </t>
  </section>

  <section title="Synchronous Modifying Operations">
    <t>
      NFSv4 operations that modify the file system are synchronous.
      When an operation is successfully completed at the server, the client
      can trust that any data associated with the request is now in stable
      storage (the one exception is in the case of the file data in a WRITE
      operation with the UNSTABLE4 option specified).
    </t>

    <t>
      This implies that any previous operations within the same
      COMPOUND request are also reflected in stable storage.  This
      behavior enables the client's ability to recover from a
      partially executed COMPOUND request that may have resulted
      from the failure of the server.  For example, if a
      COMPOUND request contains operations A and B and the
      server is unable to send a response to the client, then depending on
      the progress the server made in servicing the request, the result of
      both operations may be reflected in stable storage or just
      operation&nbsp;A may be reflected.  The server must not have
      just the results of operation B in stable storage.
    </t>
  </section>

  <section title="Operation Values">
    <t>
      The operations encoded in the COMPOUND procedure are identified by
      operation values.  To avoid overlap with the RPC procedure numbers,
      operations 0 (zero) and 1 are not defined.  Operation 2 is not
      defined but is reserved for future use with minor versioning.
    </t>
  </section>
</section>

<section anchor="sec:procedures" title="NFSv4 Procedures">

  <t>

  </t>

  <section anchor="OP_NULL" title="Procedure 0: NULL - No Operation">

    <section toc="exclude" anchor="OP_NULL_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  &lt;null&gt;
        </artwork>
      </figure>

    </section>

    <section toc="exclude" anchor="OP_NULL_ARGUMENT" title="ARGUMENT">

      <figure>
        <artwork>
  void;
        </artwork>
      </figure>

    </section>

    <section toc="exclude" anchor="OP_NULL_RESULT" title="RESULT">

      <figure>
        <artwork>
  void;
        </artwork>
      </figure>

    </section>

    <section toc="exclude" anchor="OP_NULL_DESCRIPTION" title="DESCRIPTION">

      <t>
        Standard NULL procedure.  Void argument, void response.
        This procedure has no functionality associated with it.
        Because of this, it is sometimes used to measure the overhead
        of processing a service request.  Therefore, the server
        should ensure that no unnecessary work is done in servicing
        this procedure.
      </t>

    </section>
  </section>

  <section anchor="OP_COMPOUND" title="Procedure 1: COMPOUND - COMPOUND Operations">

    <section toc="exclude" anchor="OP_COMPOUND_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  compoundargs -> compoundres
        </artwork>
      </figure>

    </section>

    <section toc="exclude" anchor="OP_COMPOUND_ARGUMENT" title="ARGUMENT">

      <figure>
        <artwork>
  union nfs_argop4 switch (nfs_opnum4 argop) {
          case &lt;OPCODE&gt;: &lt;argument&gt;;
          ...
  };
        </artwork>
      </figure>

<figure>
 <artwork>
struct COMPOUND4args {
        utf8str_cs      tag;
        uint32_t        minorversion;
        nfs_argop4      argarray&lt;>;
};
 </artwork>
</figure>

    </section>

    <section toc="exclude" anchor="OP_COMPOUND_RESULT" title="RESULT">

      <figure>
        <artwork>
  union nfs_resop4 switch (nfs_opnum4 resop) {
          case &lt;OPCODE&gt;: &lt;argument&gt;;
          ...
  };
        </artwork>
      </figure>

<figure>
 <artwork>
struct COMPOUND4res {
        nfsstat4        status;
        utf8str_cs      tag;
        nfs_resop4      resarray&lt;>;
};
 </artwork>
</figure>

    </section>

    <section toc="exclude" anchor="OP_COMPOUND_DESCRIPTION" title="DESCRIPTION">

      <t>
        The COMPOUND procedure is used to combine one or more of
        the NFS operations into a single RPC request.  The main
        NFS RPC program has two main procedures: NULL and COMPOUND.
        All other operations use the COMPOUND procedure as a wrapper.
      </t>

      <t>
        The COMPOUND procedure is used to combine individual operations
        into a single RPC request.  The server interprets each of
        the operations in turn.  If an operation is executed by the
        server and the status of that operation is NFS4_OK, then
        the next operation in the COMPOUND procedure is executed.
        The server continues this process until there are no more
        operations to be executed or one of the operations has a
        status value other than NFS4_OK.
      </t>

      <t>
        In the processing of the COMPOUND procedure, the server may
        find that it does not have the available resources to execute
        any or all of the operations within the COMPOUND sequence.
        In this case, the error NFS4ERR_RESOURCE will be returned
        for the particular operation within the COMPOUND procedure
        where the resource exhaustion occurred.  This assumes that
        all previous operations within the COMPOUND sequence have
        been evaluated successfully.  The results for all of the
        evaluated operations must be returned to the client.
      </t>

      <t>
        The server will generally choose between two methods of
        decoding the client's request.  The first would be the
        traditional one-pass XDR decode, in which decoding of the
        entire COMPOUND precedes execution of any operation within it.
        If there is an XDR decoding error in this case, an RPC XDR
        decode error would be returned.  The second method would be
        to make an initial pass to decode the basic COMPOUND request
        and then to XDR decode each of the individual operations, as
        the server is ready to execute it.  In this case, the server
        may encounter an XDR decode error during such an operation
        decode, after previous operations within the COMPOUND have
        been executed.  In this case, the server would return the
        error NFS4ERR_BADXDR to signify the decode error.
      </t>

      <t>
        The COMPOUND arguments contain a minorversion field.
        The initial and default value for this field is 0 (zero).
        This field will be used by future minor versions such that
        the client can communicate to the server what minor version is
        being requested.  If the server receives a COMPOUND procedure
        with a minorversion field value that it does not support,
        the server MUST return an error of NFS4ERR_MINOR_VERS_MISMATCH
        and a zero-length resultdata array.
      </t>

      <t>
        Contained within the COMPOUND results is a status field.
        If the results array length is non-zero, this status must
        be equivalent to the status of the last operation that was
        executed within the COMPOUND procedure.  Therefore, if an
        operation incurred an error, then the status value will be
        the same error value as is being returned for the operation
        that failed.
      </t>

      <t>
        Note that operations 0 (zero), 1 (one), and 2 (two) are
        not defined for the COMPOUND procedure.  It is possible
        that the server receives a request that contains an operation
        that is less than the first legal operation (OP_ACCESS) or
        greater than the last legal operation (OP_RELEASE_LOCKOWNER).
        In this case, the server's response will encode the opcode
        OP_ILLEGAL rather than the illegal opcode of the request.
        The status field in the ILLEGAL return results will be set to
        NFS4ERR_OP_ILLEGAL.  The COMPOUND procedure's return results
        will also be NFS4ERR_OP_ILLEGAL.
      </t>

      <t>
        The definition of the "tag" in the request is left to the
        implementer.  It may be used to summarize the content of
        the COMPOUND request for the benefit of packet sniffers and
        engineers debugging implementations.  However, the value of
        "tag" in the response SHOULD be the same value as the value
        provided in the request.  This applies to the tag field of the
        CB_COMPOUND procedure as well.
      </t>

      <section toc="exclude" anchor="current_filehandle" title="Current Filehandle">
        <t>
          The current filehandle and the saved filehandle are used
          throughout the protocol.  Most operations implicitly use
          the current filehandle as an argument, and many set
          the current filehandle as part of the results.
          The combination of client-specified sequences
          of operations and current and saved filehandle
          arguments and results allows for greater protocol
          flexibility.  The best or easiest example of current
          filehandle usage is a sequence like the following:
        </t>

        <t>
          <figure anchor='curfh_example' title="Filehandle Usage Example">
            <artwork>
                     PUTFH fh1              {fh1}
                     LOOKUP "compA"         {fh2}
                     GETATTR                {fh2}
                     LOOKUP "compB"         {fh3}
                     GETATTR                {fh3}
                     LOOKUP "compC"         {fh4}
                     GETATTR                {fh4}
                     GETFH
            </artwork>
          </figure>
        </t>
        <t>
          In this example, the PUTFH (<xref target="OP_PUTFH"/>)
          operation explicitly sets the current filehandle value,
          while the result of each LOOKUP operation sets
          the current filehandle value to the resultant file system
          object.  Also, the client is able to insert GETATTR operations
          using the current filehandle as an argument.
        </t>
        <t>
          The PUTROOTFH (<xref target="OP_PUTROOTFH"/>) and
          PUTPUBFH (<xref target="OP_PUTPUBFH"/>) operations also set the
          current filehandle. The above example would replace "PUTFH fh1" with
          PUTROOTFH or PUTPUBFH with no filehandle argument in order to 
          achieve the same effect (on the assumption that "compA" is directly
          below the root of the namespace).
        </t>
        <t>
          Along with the current filehandle, there is a saved filehandle.
          While the current filehandle is set as the result of
          operations like LOOKUP, the saved filehandle must be set
          directly with the use of the SAVEFH operation.  The SAVEFH
          operation copies the current filehandle value to the saved
          value.  The saved filehandle value is used in combination with
          the current filehandle value for the LINK and RENAME
          operations.  The RESTOREFH operation will copy the saved
          filehandle value to the current filehandle value; as a result,
          the saved filehandle value may be used as a sort of
          "scratch" area for the client's series of operations.
        </t>
      </section>
  
    </section>

    <section toc="exclude" anchor="OP_COMPOUND_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        Since an error of any type may occur after only a portion
        of the operations have been evaluated, the client must be
        prepared to recover from any failure.  If the source of
        an NFS4ERR_RESOURCE error was a complex or lengthy set of
        operations, it is likely that if the number of operations were
        reduced the server would be able to evaluate them successfully.
        Therefore, the client is responsible for dealing with this
        type of complexity in recovery.
      </t>

      <t>
        A single compound should not contain multiple operations
        that have different values for the clientid field used in
        OPEN, LOCK, or RENEW.  This can cause confusion in cases in
        which operations that do not contain clientids have potential
        interactions with operations that do.  When only a single
        clientid has been used, it is clear what client is being
        referenced.  For a particular example involving the interaction
        of OPEN and GETATTR, see <xref target='OP_OPEN_IMPLEMENTATION' />.
      </t>

    </section>
   </section>
  </section>

<section anchor="sec:operations" title="NFSv4 Operations">

  <section anchor="OP_ACCESS" title="Operation 3: ACCESS - Check Access Rights">

    <section toc="exclude" anchor="OP_ACCESS_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh), accessreq -> supported, accessrights
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_ACCESS_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
const ACCESS4_READ      = 0x00000001;
const ACCESS4_LOOKUP    = 0x00000002;
const ACCESS4_MODIFY    = 0x00000004;
const ACCESS4_EXTEND    = 0x00000008;
const ACCESS4_DELETE    = 0x00000010;
const ACCESS4_EXECUTE   = 0x00000020;

struct ACCESS4args {
        /* CURRENT_FH: object */
        uint32_t        access;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_ACCESS_RESULT" title="RESULT">

<figure>
 <artwork>
struct ACCESS4resok {
        uint32_t        supported;
        uint32_t        access;
};

union ACCESS4res switch (nfsstat4 status) {
 case NFS4_OK:
         ACCESS4resok   resok4;
 default:
         void;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_ACCESS_DESCRIPTION" title="DESCRIPTION">

      <t>
        ACCESS determines the access rights that a user, as identified
        by the credentials in the RPC request, has with respect to
        the file system object specified by the current filehandle.
        The client encodes the set of access rights that are to be
        checked in the bitmask "access".  The server checks the
        permissions encoded in the bitmask.  If a status of NFS4_OK
        is returned, two bitmasks are included in the response.
        The first, "supported", represents the access rights for
        which the server can verify reliably.  The second, "access",
        represents the access rights available to the user for the
        filehandle provided.  On success, the current filehandle
        retains its value.
      </t>

      <t>
        Note that the supported field will contain only as many values
        as were originally sent in the arguments.  For example, if the
        client sends an ACCESS operation with only the ACCESS4_READ
        value set and the server supports this value, the server
        will return only ACCESS4_READ even if it could have reliably
        checked other values.
      </t>

      <t>
        The results of this operation are necessarily advisory
        in nature.  A return status of NFS4_OK and the appropriate
        bit set in the bitmask do not imply that such access will
        be allowed to the file system object in the future. This is
        because access rights can be revoked by the server at any time.
      </t>

      <t>
        The following access permissions may be requested:

        <list style='hanging'>

          <t hangText="ACCESS4_READ:">
            Read data from file or read a directory.
          </t>

          <t hangText="ACCESS4_LOOKUP:">
            Look up a name in a directory (no meaning for
            non&nbhy;directory objects).
          </t>

          <t hangText="ACCESS4_MODIFY:">
            Rewrite existing file data or modify existing directory
            entries.
          </t>

          <t hangText="ACCESS4_EXTEND:">
            Write new data or add directory entries.
          </t>

          <t hangText="ACCESS4_DELETE:">
            Delete an existing directory entry.
          </t>

          <t hangText="ACCESS4_EXECUTE:">
            Execute file (no meaning for a directory).
          </t>

        </list>
      </t>

      <t>
        On success, the current filehandle retains its value.
      </t>

    </section>
    <section toc="exclude" anchor="OP_ACCESS_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        In general, it is not sufficient for the client to attempt to
        deduce access permissions by inspecting the uid, gid, and mode
        fields in the file attributes or by attempting to interpret
        the contents of the ACL attribute.  This is because the server
        may perform uid or gid mapping or enforce additional access
        control restrictions.  It is also possible that the server
        may not be in the same ID space as the client.  In these cases
        (and perhaps others), the client cannot reliably perform an
        access check with only current file attributes.
      </t>

      <t>
        In the NFSv2 protocol, the only reliable way to
        determine whether an operation was allowed was to try it and
        see if it succeeded or failed.  Using the ACCESS operation in
        the NFSv4 protocol, the client can ask the server to
        indicate whether or not one or more classes of operations are
        permitted.  The ACCESS operation is provided to allow clients
        to check before doing a series of operations that might result
        in an access failure.  The OPEN operation provides a point
        where the server can verify access to the file object and the
        method to return that information to the client.  The ACCESS
        operation is still useful for directory operations or for use
        in the case where the UNIX API "access" is used on the client.
      </t>

      <t>
        The information returned by the server in response to an ACCESS
        call is not permanent.  It was correct at the exact time
        that the server performed the checks, but not necessarily
        afterward.  The server can revoke access permission at
        any time.
      </t>

      <t>
        The client should use the effective credentials of the user
        to build the authentication information in the ACCESS request
        used to determine access rights.  It is the effective user
        and group credentials that are used in subsequent READ and
        WRITE operations.
      </t>

      <t>
        Many implementations do not directly support the ACCESS4_DELETE
        permission.  Operating systems like UNIX will ignore
        the ACCESS4_DELETE bit if set on an access request on a
        non-directory object.  In these systems, delete permission on a
        file is determined by the access permissions on the directory
        in which the file resides, instead of being determined by the
        permissions of the file itself.  Therefore, the mask returned
        enumerating which access rights can be supported will have
        the ACCESS4_DELETE value set to 0.  This indicates to the
        client that the server was unable to check that particular
        access right.  The ACCESS4_DELETE bit in the access mask
        returned will then be ignored by the client.
      </t>

    </section>
  </section>
  <section anchor="OP_CLOSE" title="Operation 4: CLOSE - Close File">

    <section toc="exclude" anchor="OP_CLOSE_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh), seqid, open_stateid -> open_stateid
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_CLOSE_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct CLOSE4args {
        /* CURRENT_FH: object */
        seqid4          seqid;
        stateid4        open_stateid;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_CLOSE_RESULT" title="RESULT">

<figure>
 <artwork>
union CLOSE4res switch (nfsstat4 status) {
 case NFS4_OK:
         stateid4       open_stateid;
 default:
         void;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_CLOSE_DESCRIPTION" title="DESCRIPTION">

      <t>
        The CLOSE operation releases share reservations for the regular
        or named attribute file as specified by the current filehandle.
        The share reservations and other state information released at
        the server as a result of this CLOSE are only associated with
        the supplied stateid.  The sequence id provides for the correct
        ordering. State associated with other OPENs is not affected.
      </t>

      <t>
        If byte-range locks are held, the client SHOULD release all locks
        before issuing a CLOSE.  The server MAY free all outstanding
        locks on CLOSE, but some servers may not support the CLOSE
        of a file that still has byte-range locks held.  The server MUST
        return failure if any locks would exist after the CLOSE.
      </t>

      <t>
        On success, the current filehandle retains its value.
      </t>

    </section>
    <section toc="exclude" anchor="OP_CLOSE_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        Even though CLOSE returns a stateid, this stateid is not
        useful to the client and should be treated as deprecated.
        CLOSE "shuts down" the state associated with all OPENs for
        the file by a single open-owner.  As noted above, CLOSE will
        either release all file locking state or return an error.
        Therefore, the stateid returned by CLOSE is not useful for
        the operations that follow.
      </t>

    </section>
  </section>
  <section anchor="OP_COMMIT" title="Operation 5: COMMIT - Commit Cached Data">

    <section toc="exclude" anchor="OP_COMMIT_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh), offset, count -> verifier
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_COMMIT_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct COMMIT4args {
        /* CURRENT_FH: file */
        offset4         offset;
        count4          count;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_COMMIT_RESULT" title="RESULT">

<figure>
 <artwork>
struct COMMIT4resok {
        verifier4       writeverf;
};

union COMMIT4res switch (nfsstat4 status) {
 case NFS4_OK:
         COMMIT4resok   resok4;
 default:
         void;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_COMMIT_DESCRIPTION" title="DESCRIPTION">

      <t>
        The COMMIT operation forces or flushes data to stable
        storage for the file specified by the current filehandle.
        The flushed data is that which was previously written with
        a WRITE operation that had the stable field set to UNSTABLE4.
      </t>

      <t>
        The offset specifies the position within the file where the
        flush is to begin.  An offset value of 0 (zero) means to
        flush data starting at the beginning of the file.  The count
        specifies the number of bytes of data to flush.  If count is 0
        (zero), a flush from the offset to the end of the file is done.
      </t>

      <t>
        The server returns a write verifier upon successful completion
        of the COMMIT.  The write verifier is used by the client to
        determine if the server has restarted or rebooted between
        the initial WRITE(s) and the COMMIT.  The client does this
        by comparing the write verifier returned from the initial
        writes and the verifier returned by the COMMIT operation.
        The server must vary the value of the write verifier at each
        server event or instantiation that may lead to a loss of
        uncommitted data.  Most commonly, this occurs when the server
        is rebooted; however, other events at the server may result
        in uncommitted data loss as well.
      </t>

      <t>
        On success, the current filehandle retains its value.
      </t>

    </section>
    <section toc="exclude" anchor="OP_COMMIT_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        The COMMIT operation is similar in operation and semantics
        to the POSIX fsync() <xref target="fsync" /> system call that synchronizes a file's
        state with the disk (file data and metadata are flushed to
        disk or stable storage).  COMMIT performs the same operation
        for a client, flushing any unsynchronized data and metadata
        on the server to the server's disk or stable storage for
        the specified file.  Like fsync(), it may be that there
        is some modified data or no modified data to synchronize.
        The data may have been synchronized by the server's normal
        periodic buffer synchronization activity.  COMMIT should
        return NFS4_OK, unless there has been an unexpected error.
      </t>

      <t>
        COMMIT differs from fsync() in that it is possible for the
        client to flush a range of the file (most likely triggered
        by a buffer-reclamation scheme on the client before the
        file has been completely written).
      </t>

      <t>
        The server implementation of COMMIT is reasonably simple.
        If the server receives a full file COMMIT request that is
        starting at offset 0 and count 0, it should do the equivalent
        of fsync()'ing the file.  Otherwise, it should arrange to
        have the cached data in the range specified by offset and
        count to be flushed to stable storage.  In both cases, any
        metadata associated with the file must be flushed to stable
        storage before returning.  It is not an error for there to be
        nothing to flush on the server.  This means that the data and
        metadata that needed to be flushed have already been flushed
        or lost during the last server failure.
      </t>

      <t>
        The client implementation of COMMIT is a little more complex.
        There are two reasons for wanting to commit a client buffer
        to stable storage.  The first is that the client wants
        to reuse a buffer.  In this case, the offset and count of
        the buffer are sent to the server in the COMMIT request.
        The server then flushes any cached data based on the offset
        and count, and flushes any metadata associated with the file.
        It then returns the status of the flush and the write verifier.
        The other reason for the client to generate a COMMIT is for a
        full file flush, such as may be done at CLOSE.  In this case,
        the client would gather all of the buffers for this file that
        contain uncommitted data, do the COMMIT operation with an
        offset of 0 and count of 0, and then free all of those buffers.
        Any other dirty buffers would be sent to the server in the
        normal fashion.
      </t>

      <t>
        After a buffer is written by the client with the stable
        parameter set to UNSTABLE4, the buffer must be considered
        modified by the client until the buffer has been either flushed
        via a COMMIT operation or written via a WRITE operation with
        the stable parameter set to FILE_SYNC4 or DATA_SYNC4. This is
        done to prevent the buffer from being freed and reused before the
        data can be flushed to stable storage on the server.
      </t>

      <t>
        When a response is returned from either a WRITE or a COMMIT
        operation and it contains a write verifier that is different
        than previously returned by the server, the client will
        need to retransmit all of the buffers containing uncommitted
        cached data to the server.  How this is to be done is up to
        the implementer.  If there is only one buffer of interest,
        then it should probably be sent back over in a WRITE request
        with the appropriate stable parameter.  If there is more
        than one buffer, it might be worthwhile to retransmit all of
        the buffers in WRITE requests with the stable parameter set
        to UNSTABLE4 and then retransmit the COMMIT operation to flush
        all of the data on the server to stable storage.  The timing
        of these retransmissions is left to the implementer.
      </t>

      <t>
        The above description applies to page-cache-based systems
        as well as buffer-cache-based systems.  In those systems,
        the virtual memory system will need to be modified instead
        of the buffer cache.
      </t>

    </section>
  </section>
  <section anchor="OP_CREATE" title="Operation 6: CREATE - Create a Non-regular File Object">

    <section toc="exclude" anchor="OP_CREATE_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh), name, type, attrs -> (cfh), cinfo, attrset
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_CREATE_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
union createtype4 switch (nfs_ftype4 type) {
 case NF4LNK:
         linktext4 linkdata;
 case NF4BLK:
 case NF4CHR:
         specdata4 devdata;
 case NF4SOCK:
 case NF4FIFO:
 case NF4DIR:
         void;
 default:
         void;  /* server should return NFS4ERR_BADTYPE */
};

struct CREATE4args {
        /* CURRENT_FH: directory for creation */
        createtype4     objtype;
        component4      objname;
        fattr4          createattrs;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_CREATE_RESULT" title="RESULT">

<figure>
 <artwork>
struct CREATE4resok {
        change_info4    cinfo;
        bitmap4         attrset;        /* attributes set */
};

union CREATE4res switch (nfsstat4 status) {
 case NFS4_OK:
         CREATE4resok resok4;
 default:
         void;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_CREATE_DESCRIPTION" title="DESCRIPTION">

      <t>
        The CREATE operation creates a non-regular file object in
        a directory with a given name.  The OPEN operation is
        used to create a regular file.
      </t>

      <t>
        The objname specifies the name for the new object.  The objtype
        determines the type of object to be created: directory,
        symlink, etc.
      </t>

      <t>
        If an object of the same name already exists in the directory,
        the server will return the error NFS4ERR_EXIST.
      </t>

      <t>
        For the directory where the new file object was created, the
        server returns change_info4 information in cinfo.  With the
        atomic field of the change_info4 struct, the server will
        indicate if the before and after change attributes were
        obtained atomically with respect to the file object creation.
      </t>

      <t>
        If the objname is of zero length, NFS4ERR_INVAL will
        be returned.  The objname is also subject to the normal
        UTF-8, character support, and name checks.  See 
        <xref target="ss:i18n:utf8_err" />
        for further discussion.
      </t>

      <t>
        The current filehandle is replaced by that of the new object.
      </t>

      <t>
        The createattrs field specifies the initial set of attributes for
        the object.  The set of attributes may include any writable
        attribute valid for the object type. When the operation is
        successful, the server will return to the client an attribute
        mask signifying which attributes were successfully set for
        the object.
      </t>

      <t>
        If createattrs includes neither the owner attribute nor an
        ACL with an ACE for the owner, and if the server's file system
        both supports and requires an owner attribute (or an owner
        ACE), then the server MUST derive the owner (or the owner
        ACE). This would typically be from the principal indicated in
        the RPC credentials of the call, but the server's operating
        environment or file system semantics may dictate other methods
        of derivation. Similarly, if createattrs includes neither the
        group attribute nor a group ACE, and if the server's file system
        both supports and requires the notion of a group attribute
        (or group ACE), the server MUST derive the group attribute
        (or the corresponding owner ACE) for the file. This could be
        from the RPC's credentials, such as the group principal
        if the credentials include it (such as with AUTH_SYS), from
        the group identifier associated with the principal in the
        credentials (e.g., POSIX systems have a user database <xref target="getpwnam" />
        that has the group identifier for every user identifier),
        inherited from the directory the object is created in, or whatever
        else the server's operating environment or file system semantics
        dictate. This applies to the OPEN operation too.
      </t>

      <t>
        Conversely, it is possible the client will specify in
        createattrs an owner attribute, group attribute, or ACL
        that the principal indicated the RPC's credentials does
        not have permissions to create files for. The error to be
        returned in this instance is NFS4ERR_PERM. This applies to
        the OPEN operation too.
      </t>

    </section>
    <section toc="exclude" anchor="OP_CREATE_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        If the client desires to set attribute values after the create,
        a SETATTR operation can be added to the COMPOUND request so
        that the appropriate attributes will be set.
      </t>

    </section>
  </section>
  <section anchor="OP_DELEGPURGE" title="Operation 7: DELEGPURGE - Purge Delegations Awaiting Recovery">

    <section toc="exclude" anchor="OP_DELEGPURGE_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  clientid ->
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_DELEGPURGE_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct DELEGPURGE4args {
        clientid4       clientid;
};

 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_DELEGPURGE_RESULT" title="RESULT">

<figure>
 <artwork>
struct DELEGPURGE4res {
        nfsstat4        status;
};

 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_DELEGPURGE_DESCRIPTION" title="DESCRIPTION">

      <t>
        DELEGPURGE purges all of the delegations awaiting recovery
        for a given client.  This is useful for clients that do not
        commit delegation information to stable storage, to indicate
        that conflicting requests need not be delayed by the server
        awaiting recovery of delegation information.
      </t>

      <t>
        This operation is provided to support clients that record delegation
        information in stable storage on the client.  In this case,
        DELEGPURGE should be issued immediately after doing delegation
        recovery (using CLAIM_DELEGATE_PREV) on all delegations known to
        the client.  Doing so will notify the server that no additional
        delegations for the client will be recovered, allowing it to free
        resources and avoid delaying other clients who make requests that
        conflict with the unrecovered delegations.  All clients SHOULD use
        DELEGPURGE as part of recovery once it is known that no further
        CLAIM_DELEGATE_PREV recovery will be done.  This includes clients
        that do not record delegation information in stable storage, who would
        then do a DELEGPURGE immediately after SETCLIENTID_CONFIRM.
      </t>

      <t>
        The set of delegations known to the server and the
        client may be different.  The reasons for this include:
      </t>

      <t>
        <list style='symbols'>
          <t>
            A client may fail after making a request that resulted in delegation
            but before it received the results and committed them to the client's
            stable storage.
          </t>

          <t>
            A client may fail after deleting its indication that a delegation exists
            but before the delegation return is fully processed by the server.
          </t>

          <t>
            In the case in which the server and the client restart, the server
            may have limited persistent recording of delegations to a subset
            of those in existence.
          </t>

          <t>
            A client may have only persistently recorded information about a subset of
            delegations.
          </t>
        </list>
      </t>

      <t>
        The server MAY support DELEGPURGE, but its support or non-support should
        match that of CLAIM_DELEGATE_PREV:
      </t>

      <t>
        <list style='symbols'>
          <t>
            A server may support both DELEGPURGE and CLAIM_DELEGATE_PREV.
          </t>

          <t>
            A server may support neither DELEGPURGE nor CLAIM_DELEGATE_PREV.
          </t>
        </list>
      </t>

      <t>
        This fact allows a client starting up to determine if the server is prepared
        to support persistent storage of delegation information and thus whether it
        may use write-back caching to local persistent storage, relying on
        CLAIM_DELEGATE_PREV recovery to allow such changed data to be flushed
        safely to the server in the event of client restart.
      </t>
    </section>
  </section>

  <section anchor="OP_DELEGRETURN" title="Operation 8: DELEGRETURN - Return Delegation">
    <section toc="exclude" anchor="OP_DELEGRETURN_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh), stateid ->
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_DELEGRETURN_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct DELEGRETURN4args {
        /* CURRENT_FH: delegated file */
        stateid4        deleg_stateid;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_DELEGRETURN_RESULT" title="RESULT">

<figure>
 <artwork>
struct DELEGRETURN4res {
        nfsstat4        status;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_DELEGRETURN_DESCRIPTION" title="DESCRIPTION">

      <t>
        DELEGRETURN returns the delegation represented by the current
        filehandle and stateid.
      </t>

      <t>
        Delegations may be returned when recalled or voluntarily
        (i.e., before the server has recalled them).  In either case,
        the client must properly propagate state changed under the
        context of the delegation to the server before returning
        the delegation.
      </t>

    </section>
  </section>
  <section anchor="OP_GETATTR" title="Operation 9: GETATTR - Get Attributes">

    <section toc="exclude" anchor="OP_GETATTR_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh), attrbits -> attrbits, attrvals
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_GETATTR_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct GETATTR4args {
        /* CURRENT_FH: directory or file */
        bitmap4         attr_request;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_GETATTR_RESULT" title="RESULT">

<figure>
 <artwork>
struct GETATTR4resok {
        fattr4          obj_attributes;
};

union GETATTR4res switch (nfsstat4 status) {
 case NFS4_OK:
         GETATTR4resok  resok4;
 default:
         void;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_GETATTR_DESCRIPTION" title="DESCRIPTION">

      <t>
        The GETATTR operation will obtain attributes for the file system
        object specified by the current filehandle.  The client
        sets a bit in the bitmap argument for each attribute value
        that it would like the server to return.  The server returns
        an attribute bitmap that indicates the attribute values for
        which it was able to return values, followed by the attribute values
        ordered lowest attribute number first.
      </t>

      <t>
        The server MUST return a value for each attribute that
        the client requests if the attribute is supported by the
        server.  If the server does not support an attribute or
        cannot approximate a useful value, then it MUST NOT return
        the attribute value and MUST NOT set the attribute bit in
        the result bitmap.  The server MUST return an error if it
        supports an attribute on the target but cannot obtain its
        value.  In that case, no attribute values will be returned.
      </t>

      <t>
        File systems that are absent should be treated as having support for
        a very small set of attributes as described in
        <xref target="absent_getattr"></xref> -- even if previously, when
        the file system was present, more attributes were supported.
      </t>

      <t>
        All servers MUST support the REQUIRED attributes, as specified
        in <xref target="file_attributes"></xref>, for all file systems,
        with the exception of absent file systems.
      </t>

      <t>
        On success, the current filehandle retains its value.
      </t>

    </section>
    <section toc="exclude" anchor="OP_GETATTR_IMPLEMENTATION" title="IMPLEMENTATION">

    <t>
      Suppose there is an OPEN_DELEGATE_WRITE delegation held by another
      client for the file in question, and size and/or change are among
      the set of attributes being interrogated. The server has two choices.
      First, the server can obtain the actual current value of these
      attributes from the client holding the delegation by using
      the CB_GETATTR callback.  Second, the server, particularly when
      the delegated client is unresponsive, can recall the
      delegation in question.  The GETATTR MUST NOT proceed
      until one of the following occurs:
      <list style="symbols">
        <t>
          The requested attribute values are returned in the response to
          CB_GETATTR.
        </t>
        <t>
          The OPEN_DELEGATE_WRITE delegation is returned.
        </t>
        <t>
          The OPEN_DELEGATE_WRITE delegation is revoked.
        </t>
      </list>
    </t>
    <t>
      Unless one of the above happens very quickly,
      one or more NFS4ERR_DELAY errors will be returned
      while a delegation is outstanding.
    </t>

    </section>
  </section>
  <section anchor="OP_GETFH" title="Operation 10: GETFH - Get Current Filehandle">

    <section toc="exclude" anchor="OP_GETFH_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh) -> filehandle
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_GETFH_ARGUMENT" title="ARGUMENT">

      <figure>
        <artwork>
  /* CURRENT_FH: */
  void;
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_GETFH_RESULT" title="RESULT">

<figure>
 <artwork>
struct GETFH4resok {
        nfs_fh4         object;
};

union GETFH4res switch (nfsstat4 status) {
 case NFS4_OK:
         GETFH4resok     resok4;
 default:
         void;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_GETFH_DESCRIPTION" title="DESCRIPTION">

      <t>
        This operation returns the current filehandle value.
      </t>

      <t>
        On success, the current filehandle retains its value.
      </t>

    </section>
    <section toc="exclude" anchor="OP_GETFH_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        Operations that change the current filehandle, like LOOKUP
        or CREATE, do not automatically return the new filehandle
        as a result.  For instance, if a client needs to look up a
        directory entry and obtain its filehandle, then the following
        request is needed.
      </t>

      <figure>
        <artwork>
  PUTFH  (directory filehandle)
  LOOKUP (entry name)
  GETFH
        </artwork>
      </figure>

    </section>
  </section>
  <section anchor="OP_LINK" title="Operation 11: LINK - Create Link to a File">

    <section toc="exclude" anchor="OP_LINK_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (sfh), (cfh), newname -> (cfh), cinfo
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_LINK_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct LINK4args {
        /* SAVED_FH: source object */
        /* CURRENT_FH: target directory */
        component4      newname;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_LINK_RESULT" title="RESULT">

<figure>
 <artwork>
struct LINK4resok {
        change_info4    cinfo;
};

union LINK4res switch (nfsstat4 status) {
 case NFS4_OK:
         LINK4resok resok4;
 default:
         void;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_LINK_DESCRIPTION" title="DESCRIPTION">

      <t>
        The LINK operation creates an additional newname for the
        file represented by the saved filehandle, as set by the
        SAVEFH operation, in the directory represented by the current
        filehandle.  The existing file and the target directory must
        reside within the same file system on the server.  On success,
        the current filehandle will continue to be the target
        directory.  If an object exists in the target directory with
        the same name as newname, the server must return NFS4ERR_EXIST.
      </t>

      <t>
        For the target directory, the server returns change_info4
        information in cinfo.  With the atomic field of the
        change_info4 struct, the server will indicate if the before
        and after change attributes were obtained atomically with
        respect to the link creation.
      </t>

      <t>
        If newname has a length of 0 (zero), or if newname does
        not obey the UTF-8 definition, the error NFS4ERR_INVAL will
        be returned.
      </t>

    </section>
    <section toc="exclude" anchor="OP_LINK_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        Changes to any property of the "hard" linked files are
        reflected in all of the linked files.  When a link is made
        to a file, the attributes for the file should have a value
        for numlinks that is one greater than the value before the
        LINK operation.
      </t>

      <t>
        The statement "file and the target directory must reside within the
        same file system on the server" means that the fsid fields in the
        attributes for the objects are the same.  If they reside on different
        file systems, the error NFS4ERR_XDEV is returned.  This error may be
        returned by some servers when there is an internal partitioning of a
        file system that the LINK operation would violate.
      </t>

      <t>
        On some servers, "." and ".." are illegal values for newname, and the
        error NFS4ERR_BADNAME will be returned if they are specified.
      </t>

      <t>
        When the current filehandle designates a named attribute directory
        and the object to be linked (the saved filehandle) is not a named
        attribute for the same object, the error NFS4ERR_XDEV MUST be
        returned.  When the saved filehandle designates a named attribute and
        the current filehandle is not the appropriate named attribute
        directory, the error NFS4ERR_XDEV MUST also be returned.
      </t>

      <t>
        When the current filehandle designates a named attribute directory
        and the object to be linked (the saved filehandle) is a named
        attribute within that directory, the server MAY return the error
        NFS4ERR_NOTSUPP.
      </t>

      <t>
        In the case that newname is already linked to the file represented by
        the saved filehandle, the server will return NFS4ERR_EXIST.
      </t>

      <t>
        Note that symbolic links are created with the CREATE operation.
      </t>

    </section>
  </section>
  <section anchor="OP_LOCK" title="Operation 12: LOCK - Create Lock">

    <section toc="exclude" anchor="OP_LOCK_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh) locktype, reclaim, offset, length, locker -> stateid
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_LOCK_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
enum nfs_lock_type4 {
        READ_LT         = 1,
        WRITE_LT        = 2,
        READW_LT        = 3,    /* blocking read */
        WRITEW_LT       = 4     /* blocking write */
};
 </artwork>
</figure>
<figure>
 <artwork>
/*
 * For LOCK, transition from open_owner to new lock_owner
 */
struct open_to_lock_owner4 {
        seqid4          open_seqid;
        stateid4        open_stateid;
        seqid4          lock_seqid;
        lock_owner4     lock_owner;
};

/*
 * For LOCK, existing lock_owner continues to request file locks
 */
struct exist_lock_owner4 {
        stateid4        lock_stateid;
        seqid4          lock_seqid;
};

union locker4 switch (bool new_lock_owner) {
 case TRUE:
         open_to_lock_owner4     open_owner;
 case FALSE:
         exist_lock_owner4       lock_owner;
};

/*
 * LOCK/LOCKT/LOCKU: Record lock management
 */
struct LOCK4args {
        /* CURRENT_FH: file */
        nfs_lock_type4  locktype;
        bool            reclaim;
        offset4         offset;
        length4         length;
        locker4         locker;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_LOCK_RESULT" title="RESULT">

<figure>
 <artwork>
struct LOCK4denied {
        offset4         offset;
        length4         length;
        nfs_lock_type4  locktype;
        lock_owner4     owner;
};

struct LOCK4resok {
        stateid4        lock_stateid;
};

union LOCK4res switch (nfsstat4 status) {
 case NFS4_OK:
         LOCK4resok     resok4;
 case NFS4ERR_DENIED:
         LOCK4denied    denied;
 default:
         void;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_LOCK_DESCRIPTION" title="DESCRIPTION">

      <t>
        The LOCK operation requests a byte-range lock for the byte range
        specified by the offset and length parameters.  The lock type
        is also specified to be one of the nfs_lock_type4s.  If this
        is a reclaim request, the reclaim parameter will be TRUE.
      </t>

      <t>
        Bytes in a file may be locked even if those bytes are not
        currently allocated to the file.  To lock the file from a
        specific offset through the end-of-file (no matter how long
        the file actually is), use a length field with all bits set to
        1 (one).  If the length is zero, or if a length that is not
        all bits set to one is specified, and the length when added to
        the offset exceeds the maximum 64-bit unsigned integer value,
        the error NFS4ERR_INVAL will result.
      </t>

      <t>
      32-bit servers are servers that support locking for byte offsets that
      fit within 32 bits (i.e., less than or equal to NFS4_UINT32_MAX).  If
      the client specifies a range that overlaps one or more bytes beyond
      offset NFS4_UINT32_MAX but does not end at offset NFS4_UINT64_MAX,
      then such a 32-bit server MUST return the error NFS4ERR_BAD_RANGE.
      </t>

      <t>
        In the case that the lock is denied, the owner, offset,
        and length of a conflicting lock are returned.
      </t>

      <t>
        On success, the current filehandle retains its value.
      </t>

    </section>
    <section toc="exclude" anchor="OP_LOCK_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        If the server is unable to determine the exact offset and
        length of the conflicting lock, the same offset and length
        that were provided in the arguments should be returned in
        the denied results.  <xref target="sec:lock_share" />
        contains a full
        description of this and the other file locking operations.
      </t>

      <t>
        LOCK operations are subject to permission checks and to checks
        against the access type of the associated file.  However, the
        specific rights and modes required for various types of locks
        reflect the semantics of the server-exported file system,
        and are not specified by the protocol.  For example, Windows
        2000 allows a write lock of a file open for READ, while a
        POSIX-compliant system does not.
      </t>

      <t>
        When the client makes a lock request that corresponds to a
        range that the lock-owner has locked already (with the same
        or different lock type), or to a sub-region of such a range,
        or to a region that includes multiple locks already granted
        to that lock-owner, in whole or in part, and the server does
        not support such locking operations (i.e., does not support
        POSIX locking semantics), the server will return the error
        NFS4ERR_LOCK_RANGE.  In that case, the client may return an
        error, or it may emulate the required operations, using only
        LOCK for ranges that do not include any bytes already locked
        by that lock-owner and LOCKU of locks held by that lock-owner
        (specifying an exactly matching range and type).  Similarly,
        when the client makes a lock request that amounts to upgrading
        (changing from a read lock to a write lock) or downgrading
        (changing from a write lock to a read lock) an existing record
        lock and the server does not support such a lock, the server
        will return NFS4ERR_LOCK_NOTSUPP.  Such operations may not
        perfectly reflect the required semantics in the face of
        conflicting lock requests from other clients.
      </t>

      <t>
        When a client holds an OPEN_DELEGATE_WRITE delegation, the client
        holding that delegation is assured that there are no opens by other
        clients.  Thus, there can be no conflicting LOCK operations from such
        clients.  Therefore, the client may be handling locking requests
        locally, without doing LOCK operations on the server.  If it does
        that, it must be prepared to update the lock status on the server by
        sending appropriate LOCK and LOCKU operations before returning the
        delegation.
      </t>

      <t>
        When one or more clients hold OPEN_DELEGATE_READ delegations, any
        LOCK operation where the server is implementing mandatory locking
        semantics MUST result in the recall of all such delegations.  The
        LOCK operation may not be granted until all such delegations are
        returned or revoked.  Except where this happens very quickly, one or
        more NFS4ERR_DELAY errors will be returned to requests made while the
        delegation remains outstanding.
      </t>
      <t>
        The locker argument specifies the lock-owner that is associated with
        the LOCK request.  The locker4 structure is a switched union that
        indicates whether the client has already created byte-range locking
        state associated with the current open file and lock-owner.  There
        are multiple cases to be considered, corresponding to possible 
        combinations of whether locking state has been created for the current 
        open file and lock-owner, and whether the boolean new_lock_owner is set.
        In all of the cases, there is a lock_seqid specified, whether the 
        lock-owner is specified explicitly or implicitly.  This seqid value 
        is used 
        for checking lock-owner sequencing/replay issues.  When the given 
        lock-owner is not known to the server, this establishes an initial 
        sequence value for the new lock-owner.
        <list style='symbols'>
          <t> 
            In the case in which the state has been created and the boolean is
            false, the only part of the argument 
            other than lock_seqid is just a stateid representing
            the set of locks associated with that open file and lock-owner. 
          </t> 
          <t> 
            In the case in which the state has been created and the boolean is
            true, the server rejects the request with the error 
            NFS4ERR_BAD_SEQID.  The only exception is where there is a
            retransmission of a previous request in which the boolean was true.
            In this case, the lock_seqid will match the original request, and 
            the response will reflect the final case, below. 
          </t> 
          <t> 
            In the case where no byte-range locking
                  state has been established and the boolean is true, the argument
            contains an open_to_lock_owner structure that specifies the 
            stateid of the open file and the lock-owner to be used for 
            the lock.  Note
            that although the open-owner is not given explicitly, the 
            open_seqid associated with it is used to check for 
            open-owner sequencing issues. This case provides a method to 
            use the established state of the 
            open_stateid to transition to the use of a lock stateid. 
          </t> 
        </list> 
      </t>

    </section>
  </section>
  <section anchor="OP_LOCKT" title="Operation 13: LOCKT - Test for Lock">

    <section toc="exclude" anchor="OP_LOCKT_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh) locktype, offset, length, owner -> {void, NFS4ERR_DENIED ->
  owner}
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_LOCKT_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct LOCKT4args {
        /* CURRENT_FH: file */
        nfs_lock_type4  locktype;
        offset4         offset;
        length4         length;
        lock_owner4     owner;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_LOCKT_RESULT" title="RESULT">

<figure>
 <artwork>
union LOCKT4res switch (nfsstat4 status) {
 case NFS4ERR_DENIED:
         LOCK4denied    denied;
 case NFS4_OK:
         void;
 default:
         void;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_LOCKT_DESCRIPTION" title="DESCRIPTION">

      <t>
        The LOCKT operation tests the lock as specified in the
        arguments.  If a conflicting lock exists, the owner, offset,
        length, and type of the conflicting lock are returned; if
        no lock is held, nothing other than NFS4_OK is returned.
        Lock types READ_LT and READW_LT are processed in the same
        way in that a conflicting lock test is done without regard
        to blocking or non-blocking.  The same is true for WRITE_LT
        and WRITEW_LT.
      </t>

      <t>
        The ranges are specified as for LOCK.  The NFS4ERR_INVAL
        and NFS4ERR_BAD_RANGE errors are returned under the same
        circumstances as for LOCK.
      </t>

      <t>
        On success, the current filehandle retains its value.
      </t>

    </section>
    <section toc="exclude" anchor="OP_LOCKT_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        If the server is unable to determine the exact offset and
        length of the conflicting lock, the same offset and length
        that were provided in the arguments should be returned in the
        denied results.  <xref target="sec:lock_share" />
        contains further discussion of the file locking mechanisms.
      </t>

      <t>
        LOCKT uses a lock_owner4, rather than a stateid4 as is used in
        LOCK, to identify the owner.  This is because the client does not
        have to open the file to test for the existence of a lock,
        so a stateid may not be available.
      </t>

      <t>
        The test for conflicting locks SHOULD exclude locks for
        the current lock-owner.  Note that since such locks are
        not examined the possible existence of overlapping ranges
        may not affect the results of LOCKT.  If the server does
        examine locks that match the lock-owner for the purpose
        of range checking, NFS4ERR_LOCK_RANGE may be returned.
        In the event that it returns NFS4_OK, clients may do a LOCK
        and receive NFS4ERR_LOCK_RANGE on the LOCK request because
        of the flexibility provided to the server.
      </t>

      <t>
        When a client holds an OPEN_DELEGATE_WRITE delegation, it may choose
        (see <xref target="OP_LOCK_IMPLEMENTATION" />) to handle
        LOCK requests locally.  In such a
        case, LOCKT requests will similarly be handled locally.
      </t>

    </section>
  </section>
  <section anchor="OP_LOCKU" title="Operation 14: LOCKU - Unlock File">

    <section toc="exclude" anchor="OP_LOCKU_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh) type, seqid, stateid, offset, length -> stateid
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_LOCKU_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct LOCKU4args {
        /* CURRENT_FH: file */
        nfs_lock_type4  locktype;
        seqid4          seqid;
        stateid4        lock_stateid;
        offset4         offset;
        length4         length;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_LOCKU_RESULT" title="RESULT">

<figure>
 <artwork>
union LOCKU4res switch (nfsstat4 status) {
 case NFS4_OK:
         stateid4       lock_stateid;
 default:
         void;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_LOCKU_DESCRIPTION" title="DESCRIPTION">

      <t>
        The LOCKU operation unlocks the byte-range lock specified by
        the parameters. The client may set the locktype field to any
        value that is legal for the nfs_lock_type4 enumerated type,
        and the server MUST accept any legal value for locktype. Any
        legal value for locktype has no effect on the success or
        failure of the LOCKU operation.
      </t>

      <t>
        The ranges are specified as for LOCK.  The NFS4ERR_INVAL
        and NFS4ERR_BAD_RANGE errors are returned under the same
        circumstances as for LOCK.
      </t>

      <t>
        On success, the current filehandle retains its value.
      </t>

    </section>
    <section toc="exclude" anchor="OP_LOCKU_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        If the area to be unlocked does not correspond exactly to a
        lock actually held by the lock-owner, the server may return the
        error NFS4ERR_LOCK_RANGE.  This includes the cases where (1) 
        the area is not locked, (2) the area is a sub-range of the area
        locked, (3) it overlaps the area locked without matching exactly,
        or (4) the area specified includes multiple locks held by the
        lock-owner. In all of these cases, allowed
        by POSIX locking <xref target="fcntl" /> semantics, a client
        receiving this error should, if it desires support for such
        operations, simulate
        the operation using LOCKU on ranges corresponding to locks
        it actually holds, possibly followed by LOCK requests for
        the sub-ranges not being unlocked.
      </t>

      <t>
        When a client holds an OPEN_DELEGATE_WRITE delegation, it may choose
        (see <xref target="OP_LOCK_IMPLEMENTATION" />) to handle
        LOCK requests locally.  In such a
        case, LOCKU requests will similarly be handled locally.
      </t>

    </section>
  </section>
  <section anchor="OP_LOOKUP" title="Operation 15: LOOKUP - Look Up Filename">

    <section toc="exclude" anchor="OP_LOOKUP_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh), component -> (cfh)
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_LOOKUP_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct LOOKUP4args {
        /* CURRENT_FH: directory */
        component4      objname;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_LOOKUP_RESULT" title="RESULT">

<figure>
 <artwork>
struct LOOKUP4res {
        /* CURRENT_FH: object */
        nfsstat4        status;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_LOOKUP_DESCRIPTION" title="DESCRIPTION">

      <t>
        This operation performs a LOOKUP or finds a file system object
        using the directory specified by the current filehandle.  LOOKUP
        evaluates the component and if the object exists the current
        filehandle is replaced with the component's filehandle.
      </t>

      <t>
        If the component cannot be evaluated because either it does
        not exist or the client does not have permission to evaluate
        it, then an error will be returned, and the current filehandle
        will be unchanged.
      </t>

      <t>
        If the component is of zero length, NFS4ERR_INVAL will
        be returned.  The component is also subject to the normal
        UTF-8, character support, and name checks.  See 
        <xref target="ss:i18n:utf8_err" />
        for further discussion.
      </t>

    </section>
    <section toc="exclude" anchor="OP_LOOKUP_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        If the client wants to achieve the effect of a multi-component
        lookup, it may construct a COMPOUND request such as the
        following (and obtain each filehandle):
      </t>

      <figure>
        <artwork>
  PUTFH  (directory filehandle)
  LOOKUP "pub"
  GETFH
  LOOKUP "foo"
  GETFH
  LOOKUP "bar"
  GETFH
        </artwork>
      </figure>

      <t>
        NFSv4 servers depart from the semantics of previous
        NFS versions in allowing LOOKUP requests to cross mount points
        on the server.  The client can detect a mount point crossing
        by comparing the fsid attribute of the directory with the
        fsid attribute of the directory looked up.  If the fsids are
        different, then the new directory is a server mount point.
        UNIX clients that detect a mount point crossing will need
        to mount the server's file system.  This needs to be done to
        maintain the file object identity-checking mechanisms common
        to UNIX clients.
      </t>

      <t>
        Servers that limit NFS access to "shares" or "exported"
        file systems should provide a pseudo-file system into which
        the exported file systems can be integrated, so that clients
        can browse the server's namespace.  The clients' view of
        a pseudo-file system will be limited to paths that lead to
        exported file systems.
      </t>

      <t>
        Note: Previous versions of the protocol assigned special
        semantics to the names "." and "..".  NFSv4 assigns
        no special semantics to these names.  The LOOKUPP operator
        must be used to look up a parent directory.
      </t>

      <t>
        Note that this operation does not follow symbolic links.
        The client is responsible for all parsing of filenames,
        including filenames that are modified by symbolic links
        encountered during the lookup process.
      </t>

      <t>
        If the current filehandle supplied is not a directory but
        a symbolic link, NFS4ERR_SYMLINK is returned as the error.
        For all other non&nbhy;directory file types, the error
        NFS4ERR_NOTDIR is returned.
      </t>

    </section>
  </section>
  <section anchor="OP_LOOKUPP" title="Operation 16: LOOKUPP - Look Up Parent Directory">

    <section toc="exclude" anchor="OP_LOOKUPP_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh) -> (cfh)
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_LOOKUPP_ARGUMENT" title="ARGUMENT">

      <figure>
        <artwork>
  /* CURRENT_FH: object */
  void;
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_LOOKUPP_RESULT" title="RESULT">

<figure>
 <artwork>
struct LOOKUPP4res {
        /* CURRENT_FH: directory */
        nfsstat4        status;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_LOOKUPP_DESCRIPTION" title="DESCRIPTION">

      <t>
        The current filehandle is assumed to refer to a regular
        directory or a named attribute directory.  LOOKUPP assigns
        the filehandle for its parent directory to be the current
        filehandle.  If there is no parent directory, an NFS4ERR_NOENT
        error must be returned.  Therefore, NFS4ERR_NOENT will be
        returned by the server when the current filehandle is at the
        root or top of the server's file tree.
      </t>

    </section>
    <section toc="exclude" anchor="OP_LOOKUPP_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        As for LOOKUP, LOOKUPP will also cross mount points.
      </t>

      <t>
        If the current filehandle is not a directory or named attribute
        directory, the error NFS4ERR_NOTDIR is returned.
      </t>

      <t>
        If the current filehandle is a named attribute directory that is
        associated with a file system object via OPENATTR (i.e., not a
        subdirectory of a named attribute directory), LOOKUPP SHOULD return the
        filehandle of the associated file system object.
      </t>

    </section>
  </section>
  <section anchor="OP_NVERIFY" title="Operation 17: NVERIFY - Verify Difference in Attributes">

    <section toc="exclude" anchor="OP_NVERIFY_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh), fattr -> -
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_NVERIFY_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct NVERIFY4args {
        /* CURRENT_FH: object */
        fattr4          obj_attributes;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_NVERIFY_RESULT" title="RESULT">

<figure>
 <artwork>
struct NVERIFY4res {
        nfsstat4        status;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_NVERIFY_DESCRIPTION" title="DESCRIPTION">

      <t>
        This operation is used to prefix a sequence of operations
        to be performed if one or more attributes have changed on
        some file system object.  If all the attributes match, then
        the error NFS4ERR_SAME must be returned.
      </t>

      <t>
        On success, the current filehandle retains its value.
      </t>

    </section>
    <section toc="exclude" anchor="OP_NVERIFY_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        This operation is useful as a cache validation operator.
        If the object to which the attributes belong has changed,
        then the following operations may obtain new data associated
        with that object -- for instance, to check if a file has been
        changed and obtain new data if it has:
      </t>

      <figure>
        <artwork>
  PUTFH  (public)
  LOOKUP "foobar"
  NVERIFY attrbits attrs
  READ 0 32767
        </artwork>
      </figure>

      <t>
        In the case that a RECOMMENDED attribute is specified in
        the NVERIFY operation and the server does not support
        that attribute for the file system object, the error
        NFS4ERR_ATTRNOTSUPP is returned to the client.
      </t>

      <t>
        When the attribute rdattr_error or any write-only attribute
        (e.g., time_modify_set) is specified, the error NFS4ERR_INVAL
        is returned to the client.
      </t>

    </section>
  </section>
  <section anchor="OP_OPEN" title="Operation 18: OPEN - Open a Regular File">

    <section toc="exclude" anchor="OP_OPEN_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh), seqid, share_access, share_deny, owner, openhow, claim ->
  (cfh), stateid, cinfo, rflags, attrset, delegation
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_OPEN_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
/*
 * Various definitions for OPEN
 */
enum createmode4 {
        UNCHECKED4      = 0,
        GUARDED4        = 1,
        EXCLUSIVE4      = 2
};

union createhow4 switch (createmode4 mode) {
 case UNCHECKED4:
 case GUARDED4:
         fattr4         createattrs;
 case EXCLUSIVE4:
         verifier4      createverf;
};

enum opentype4 {
        OPEN4_NOCREATE  = 0,
        OPEN4_CREATE    = 1
};

union openflag4 switch (opentype4 opentype) {
 case OPEN4_CREATE:
         createhow4     how;
 default:
         void;
};

/* Next definitions used for OPEN delegation */
enum limit_by4 {
        NFS_LIMIT_SIZE          = 1,
        NFS_LIMIT_BLOCKS        = 2
        /* others as needed */
};

struct nfs_modified_limit4 {
        uint32_t        num_blocks;
        uint32_t        bytes_per_block;
};

union nfs_space_limit4 switch (limit_by4 limitby) {
 /* limit specified as file size */
 case NFS_LIMIT_SIZE:
         uint64_t               filesize;
 /* limit specified by number of blocks */
 case NFS_LIMIT_BLOCKS:
         nfs_modified_limit4    mod_blocks;
};

enum open_delegation_type4 {
        OPEN_DELEGATE_NONE      = 0,
        OPEN_DELEGATE_READ      = 1,
        OPEN_DELEGATE_WRITE     = 2
};

enum open_claim_type4 {
        CLAIM_NULL              = 0,
        CLAIM_PREVIOUS          = 1,
        CLAIM_DELEGATE_CUR      = 2,
        CLAIM_DELEGATE_PREV     = 3
};

struct open_claim_delegate_cur4 {
        stateid4        delegate_stateid;
        component4      file;
};

union open_claim4 switch (open_claim_type4 claim) {
 /*
  * No special rights to file.
  * Ordinary OPEN of the specified file.
  */
 case CLAIM_NULL:
         /* CURRENT_FH: directory */
         component4      file;
 /*
  * Right to the file established by an
  * open previous to server reboot.  File
  * identified by filehandle obtained at
  * that time rather than by name.
  */
 case CLAIM_PREVIOUS:
         /* CURRENT_FH: file being reclaimed */
         open_delegation_type4   delegate_type;

 /*
  * Right to file based on a delegation
  * granted by the server.  File is
  * specified by name.
  */
 case CLAIM_DELEGATE_CUR:
         /* CURRENT_FH: directory */
         open_claim_delegate_cur4        delegate_cur_info;

 /*
  * Right to file based on a delegation
  * granted to a previous boot instance
  * of the client.  File is specified by name.
  */
 case CLAIM_DELEGATE_PREV:
         /* CURRENT_FH: directory */
         component4      file_delegate_prev;
};

/*
 * OPEN: Open a file, potentially receiving an open delegation
 */
struct OPEN4args {
        seqid4          seqid;
        uint32_t        share_access;
        uint32_t        share_deny;
        open_owner4     owner;
        openflag4       openhow;
        open_claim4     claim;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_OPEN_RESULT" title="RESULT">

<figure>
 <artwork>
struct open_read_delegation4 {
 stateid4 stateid;    /* Stateid for delegation */
 bool     recall;     /* Pre-recalled flag for
                         delegations obtained
                         by reclaim (CLAIM_PREVIOUS) */

 nfsace4 permissions; /* Defines users who don't
                         need an ACCESS call to
                         open for read */
};

struct open_write_delegation4 {
 stateid4 stateid;      /* Stateid for delegation */
 bool     recall;       /* Pre-recalled flag for
                           delegations obtained
                           by reclaim
                           (CLAIM_PREVIOUS) */

 nfs_space_limit4
           space_limit; /* Defines condition that
                           the client must check to
                           determine whether the
                           file needs to be flushed
                           to the server on close */

 nfsace4   permissions; /* Defines users who don't
                           need an ACCESS call as
                           part of a delegated
                           open */
};

union open_delegation4 switch
   (open_delegation_type4 delegation_type) {
        case OPEN_DELEGATE_NONE:
                void;
        case OPEN_DELEGATE_READ:
                open_read_delegation4 read;
        case OPEN_DELEGATE_WRITE:
                open_write_delegation4 write;
};

/*
 * Result flags
 */

/* Client must confirm open */
const OPEN4_RESULT_CONFIRM      = 0x00000002;
/* Type of file locking behavior at the server */
const OPEN4_RESULT_LOCKTYPE_POSIX = 0x00000004;

struct OPEN4resok {
 stateid4       stateid;      /* Stateid for open */
 change_info4   cinfo;        /* Directory change info */
 uint32_t       rflags;       /* Result flags */
 bitmap4        attrset;      /* attribute set for create */
 open_delegation4 delegation; /* Info on any open
                                 delegation */
};

union OPEN4res switch (nfsstat4 status) {
 case NFS4_OK:
         /* CURRENT_FH: opened file */
         OPEN4resok      resok4;
 default:
         void;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_OPEN_WARNING" title="Warning to Client Implementers">

      <t>
        OPEN resembles LOOKUP in that it generates a filehandle for the
        client to use.  Unlike LOOKUP, though, OPEN creates server state
        on the filehandle.  In normal circumstances, the client can
        only release this state with a CLOSE operation.  CLOSE uses
        the current filehandle to determine which file to close.
        Therefore, the client MUST follow every OPEN operation with
        a GETFH operation in the same COMPOUND procedure.  This will
        supply the client with the filehandle such that CLOSE can be
        used appropriately.
      </t>

      <t>
        Simply waiting for the lease on the file to expire is
        insufficient because the server may maintain the state
        indefinitely as long as another client does not attempt to
        make a conflicting access to the same file.
      </t>

    </section>
    <section toc="exclude" anchor="OP_OPEN_DESCRIPTION" title="DESCRIPTION">

      <t>
        The OPEN operation creates and/or opens a regular file in
        a directory with the provided name.  If the file does not
        exist at the server and creation is desired, specification of
        the method of creation is provided by the openhow parameter.
        The client has the choice of three creation methods: UNCHECKED4,
        GUARDED4, or EXCLUSIVE4.
      </t>

      <t>
        If the current filehandle is a named attribute directory, OPEN
        will then create or open a named attribute file.  Note that
        exclusive create of a named attribute is not supported.
        If the createmode is EXCLUSIVE4 and the current filehandle
        is a named attribute directory, the server will return EINVAL.
      </t>

      <t>
        UNCHECKED4 means that the file should be created if a file
        of that name does not exist and encountering an existing
        regular file of that name is not an error.  For this type of
        create, createattrs specifies the initial set of attributes
        for the file.  The set of attributes may include any writable
        attribute valid for regular files.  When an UNCHECKED4 create
        encounters an existing file, the attributes specified by
        createattrs are not used, except that when a size of zero
        is specified, the existing file is truncated.  If GUARDED4 is
        specified, the server checks for the presence of a duplicate
        object by name before performing the create.  If a duplicate
        exists, an error of NFS4ERR_EXIST is returned as the status.
        If the object does not exist, the request is performed as
        described for UNCHECKED4.  For each of these cases (UNCHECKED4
        and GUARDED4), where the operation is successful, the server
        will return to the client an attribute mask signifying which
        attributes were successfully set for the object.
      </t>

      <t>
        EXCLUSIVE4 specifies that the server is to follow exclusive
        creation semantics, using the verifier to ensure exclusive
        creation of the target.  The server should check for the
        presence of a duplicate object by name.  If the object does not
        exist, the server creates the object and stores the verifier
        with the object.  If the object does exist and the stored
        verifier matches the verifier provided by the client, the server
        uses the existing object as the newly created object.  If the
        stored verifier does not match, then an error of NFS4ERR_EXIST
        is returned.  No attributes may be provided in this case,
        since the server may use an attribute of the target object
        to store the verifier.  If the server uses an attribute to
        store the exclusive create verifier, it will signify which
        attribute was used by setting the appropriate bit in the
        attribute mask that is returned in the results.
      </t>

      <t>
        For the target directory, the server returns change_info4
        information in cinfo.  With the atomic field of the
        change_info4 struct, the server will indicate if the before
        and after change attributes were obtained atomically with
        respect to the link creation.
      </t>

      <t>
        Upon successful creation, the current filehandle is replaced
        by that of the new object.
      </t>

      <t>
        The OPEN operation provides for Windows share reservation
        capability with the use of the share_access and share_deny
        fields of the OPEN arguments.  The client specifies at OPEN
        the required share_access and share_deny modes.  For clients
        that do not directly support SHAREs (i.e., UNIX), the expected
        deny value is DENY_NONE.  In the case that there is an existing
        share reservation that conflicts with the OPEN request, the
        server returns the error NFS4ERR_SHARE_DENIED.  For a complete
        SHARE request, the client must provide values for the owner and
        seqid fields for the OPEN argument.  For additional discussion
        of share semantics, see <xref target="ss:fl:share_res" />.
      </t>

      <t>
        In the case that the client is recovering state from a
        server failure, the claim field of the OPEN argument is
        used to signify that the request is meant to reclaim state
        previously held.
      </t>

      <t>
        The claim field of the OPEN argument is used to specify the
        file to be opened and the state information that the client
        claims to possess.  There are four basic claim types that
        cover the various situations for an OPEN.  They are as follows:

        <list style='hanging'>

          <t hangText="CLAIM_NULL:">
            For the client, this is a new OPEN request, and there is
            no previous state associated with the file for the client.
          </t>

          <t hangText="CLAIM_PREVIOUS:">
            The client is claiming basic OPEN state for a file that
            was held previous to a server reboot.  This is generally
            used when a server is returning persistent filehandles; the
            client may not have the filename to reclaim the OPEN.
          </t>

          <t hangText="CLAIM_DELEGATE_CUR:">
            The client is claiming a delegation for OPEN as granted by
            the server.  This is generally done as part of recalling
            a delegation.
          </t>

          <t hangText="CLAIM_DELEGATE_PREV:">
            The client is claiming a delegation granted to a previous
            client instance.  This claim type is for use after a
            SETCLIENTID_CONFIRM and before the corresponding DELEGPURGE
            in two situations: after a client reboot and after a lease
            expiration that resulted in loss of all lock state.  The
            server MAY support CLAIM_DELEGATE_PREV.  If it does support
            CLAIM_DELEGATE_PREV, SETCLIENTID_CONFIRM MUST NOT remove
            the client's delegation state, and the server MUST support
            the DELEGPURGE operation.
          </t>
        </list>
      </t>

      <t>
        The following errors apply to use of the CLAIM_DELEGATE_PREV
        claim type:

        <list style='symbols'>
          <t>
            NFS4ERR_NOTSUPP is returned if the server does not support this
            claim type.
          </t>

          <t>
            NFS4ERR_INVAL is returned if the reclaim is done at an inappropriate
            time, e.g., after DELEGPURGE has been done.
          </t>

          <t>
            NFS4ERR_BAD_RECLAIM is returned if the other error conditions do not
            apply and the server has no record of the delegation whose reclaim
            is being attempted.
          </t>
        </list>
      </t>

      <t>
        For OPEN requests whose claim type is other than CLAIM_PREVIOUS
        (i.e., requests other than those devoted to reclaiming opens
        after a server reboot) that reach the server during its grace
        or lease expiration period, the server returns an error of
        NFS4ERR_GRACE.
      </t>

      <t>
        For any OPEN request, the server may return an open delegation,
        which allows further opens and closes to be handled locally
        on the client as described in <xref target="ss:cc:open_dele" />.
        Note that delegation is up to the server to decide.
        The client should never assume that delegation will or will
        not be granted in a particular instance.  It should always be
        prepared for either case.  A partial exception is the reclaim
        (CLAIM_PREVIOUS) case, in which a delegation type is claimed.
        In this case, delegation will always be granted, although
        the server may specify an immediate recall in the delegation
        structure.
      </t>

      <t>
        The rflags returned by a successful OPEN allow the server
        to return information governing how the open file is to
        be handled.
      </t>

      <t>
        OPEN4_RESULT_CONFIRM indicates that the client MUST execute
        an OPEN_CONFIRM operation before using the open file.
        OPEN4_RESULT_LOCKTYPE_POSIX indicates that the server's file locking
        behavior supports the complete set of POSIX locking techniques
        <xref target="fcntl" />.
        From this, the client can choose to manage file locking state
        in such a way as to handle a mismatch of file locking management.
      </t>

      <t>
        If the component is of zero length, NFS4ERR_INVAL will
        be returned.  The component is also subject to the normal
        UTF-8, character support, and name checks.  See 
        <xref target="ss:i18n:utf8_err" /> for further discussion.
      </t>

      <t>
        When an OPEN is done and the specified open-owner already
        has the resulting filehandle open, the result is to "OR"
        together the new share and deny status, together with the
        existing status.  In this case, only a single CLOSE need be
        done, even though multiple OPENs were completed.  When such
        an OPEN is done, checking of share reservations for the new
        OPEN proceeds normally, with no exception for the existing
        OPEN held by the same owner. In this case, the stateid returned
        has an "other" field that matches that of the previous open,
        while the seqid field is incremented to reflect the
        changed status due to the new open (<xref target='ss:fl:stateids' />).
      </t>

      <t>
        If the underlying file system at the server is only accessible
        in a read-only mode and the OPEN request has specified
        OPEN4_SHARE_ACCESS_WRITE or OPEN4_SHARE_ACCESS_BOTH, the
        server will return NFS4ERR_ROFS to indicate a read-only file system.
      </t>

      <t>
        As with the CREATE operation, the server MUST derive the owner,
        owner ACE, group, or group ACE if any of the four attributes
        are required and supported by the server's file system.  For an
        OPEN with the EXCLUSIVE4 createmode, the server has no choice,
        since such OPEN calls do not include the createattrs field.
        Conversely, if createattrs is specified and includes owner
        or group (or corresponding ACEs) that the principal in the
        RPC's credentials does not have authorization to create
        files for, then the server may return NFS4ERR_PERM.
      </t>

      <t>
        In the case where an OPEN specifies a size of zero (e.g.,
        truncation) and the file has named attributes, the named
        attributes are left as is.  They are not removed.
      </t>

    </section>
    <section toc="exclude" anchor="OP_OPEN_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        The OPEN operation contains support for EXCLUSIVE4 create.
        The mechanism is similar to the support in NFSv3 <xref
        target="RFC1813" />.  As in NFSv3, this mechanism
        provides reliable exclusive creation.  Exclusive create is
        invoked when the how parameter is EXCLUSIVE4.  In this case,
        the client provides a verifier that can reasonably be expected
        to be unique.  A combination of a client identifier, perhaps
        the client network address, and a unique number generated
        by the client, perhaps the RPC transaction identifier, may
        be appropriate.
      </t>

      <t>
        If the object does not exist, the server creates the object
        and stores the verifier in stable storage. For file systems
        that do not provide a mechanism for the storage of arbitrary
        file attributes, the server may use one or more elements of
        the object metadata to store the verifier. The verifier must
        be stored in stable storage to prevent erroneous failure
        on retransmission of the request. It is assumed that an
        exclusive create is being performed because exclusive
        semantics are critical to the application. Because of the
        expected usage, exclusive create does not rely solely on the
        normally volatile duplicate request cache for storage of the
        verifier. The duplicate request cache in volatile storage
        does not survive a crash and may actually flush on a long
        network partition, opening failure windows.  In the UNIX
        local file system environment, the expected storage location
        for the verifier on creation is the metadata (timestamps)
        of the object. For this reason, an exclusive object create
        may not include initial attributes because the server would
        have nowhere to store the verifier.
      </t>

      <t>
        If the server cannot support these exclusive create semantics,
        possibly because of the requirement to commit the verifier
        to stable storage, it should fail the OPEN request with the
        error NFS4ERR_NOTSUPP.
      </t>

      <t>
        During an exclusive CREATE request, if the object already
        exists, the server reconstructs the object's verifier and
        compares it with the verifier in the request. If they match,
        the server treats the request as a success. The request is
        presumed to be a duplicate of an earlier, successful request
        for which the reply was lost and that the server duplicate
        request cache mechanism did not detect.  If the verifiers
        do not match, the request is rejected with the status
        NFS4ERR_EXIST.
      </t>

      <t>
        Once the client has performed a successful exclusive create,
        it must issue a SETATTR to set the correct object attributes.
        Until it does so, it should not rely upon any of the
        object attributes, since the server implementation may
        need to overload object metadata to store the verifier.
        The subsequent SETATTR must not occur in the same COMPOUND
        request as the OPEN.  This separation will guarantee that the
        exclusive create mechanism will continue to function properly
        in the face of retransmission of the request.
      </t>

      <t>
        Use of the GUARDED4 attribute does not provide "exactly-once"
        semantics.  In particular, if a reply is lost and the
        server does not detect the retransmission of the request,
        the operation can fail with NFS4ERR_EXIST, even though the
        create was performed successfully.  The client would use this
        behavior in the case that the application has not requested
        an exclusive create but has asked to have the file truncated
        when the file is opened.  In the case of the client timing
        out and retransmitting the create request, the client can use
        GUARDED4 to prevent a sequence such as create, write,
        create (retransmitted) from occurring.
      </t>

      <t>
        For share reservations (see <xref target='ss:fl:share_res' />), the client must specify a value
        for share_access that is one of OPEN4_SHARE_ACCESS_READ, OPEN4_SHARE_ACCESS_WRITE, or OPEN4_SHARE_ACCESS_BOTH.
        For share_deny, the client must specify one of OPEN4_SHARE_DENY_NONE, OPEN4_SHARE_DENY_READ,
        OPEN4_SHARE_DENY_WRITE, or OPEN4_SHARE_DENY_BOTH.  If the client fails to do this, the server
        must return NFS4ERR_INVAL.
      </t>

      <t>
        Based on the share_access value (OPEN4_SHARE_ACCESS_READ,
        OPEN4_SHARE_ACCESS_WRITE, or OPEN4_SHARE_ACCESS_BOTH),
        the client should check that the requester has the proper
        access rights to perform the specified operation.  This would
        generally be the results of applying the ACL access rules
        to the file for the current requester.  However, just as
        with the ACCESS operation, the client should not attempt to
        second-guess the server's decisions, as access rights may
        change and may be subject to server administrative controls
        outside the ACL framework.  If the requester is not authorized
        to READ or WRITE (depending on the share_access value), the
        server must return NFS4ERR_ACCESS.  Note that since the
        NFSv4 protocol does not impose any requirement that READs
        and WRITEs issued for an open file have the same credentials
        as the OPEN itself, the server still must do appropriate
        access checking on the READs and WRITEs themselves.
      </t>

      <t>
        If the component provided to OPEN resolves to something
        other than a regular file (or a named attribute), an error
        will be returned to the
        client.  If it is a directory, NFS4ERR_ISDIR is returned;
        otherwise, NFS4ERR_SYMLINK is returned.  Note that
        NFS4ERR_SYMLINK is returned for both symlinks and for special
        files of other types; NFS4ERR_INVAL would be inappropriate,
        since the arguments provided by the client were correct, and
        the client cannot necessarily know at the time it sent the OPEN
        that the component would resolve to a non-regular file.
      </t>

      <t>
        If the current filehandle is not a directory, the error
        NFS4ERR_NOTDIR will be returned.
      </t>

      <t>

        If a COMPOUND contains an OPEN that establishes an
        OPEN_DELEGATE_WRITE delegation, then subsequent GETATTRs
        normally result in a CB_GETATTR being sent to the client
        holding the delegation. However, in  the case in which the
        OPEN and GETATTR are part of the same COMPOUND, the server
        SHOULD understand that the operations are for the same
        client ID and avoid querying the client, which will not be
        able to respond.  This sequence of OPEN and GETATTR SHOULD be
        understood to be the retrieval of the size and change attributes
        at the time of OPEN.  Further, as explained in
        <xref target='OP_COMPOUND_IMPLEMENTATION' />, the client should
        not construct a COMPOUND that mixes operations for different
        client IDs.
      </t>

    </section>
  </section>
  <section anchor="OP_OPENATTR" title="Operation 19: OPENATTR - Open Named Attribute Directory">

    <section toc="exclude" anchor="OP_OPENATTR_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh) createdir -> (cfh)
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_OPENATTR_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct OPENATTR4args {
        /* CURRENT_FH: object */
        bool    createdir;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_OPENATTR_RESULT" title="RESULT">

<figure>
 <artwork>
struct OPENATTR4res {
        /* CURRENT_FH: named attr directory */
        nfsstat4        status;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_OPENATTR_DESCRIPTION" title="DESCRIPTION">

      <t>
        The OPENATTR operation is used to obtain the filehandle of
        the named attribute directory associated with the current
        filehandle.  The result of the OPENATTR will be a filehandle to
        an object of type NF4ATTRDIR.  From this filehandle, READDIR
        and LOOKUP operations can be used to obtain filehandles for
        the various named attributes associated with the original
        file system object.  Filehandles returned within the named
        attribute directory will have a type of NF4NAMEDATTR.
      </t>

      <t>
        The createdir argument allows the client to signify if a
        named attribute directory should be created as a result of
        the OPENATTR operation.  Some clients may use the OPENATTR
        operation with a value of FALSE for createdir to determine if
        any named attributes exist for the object.  If none exist, then
        NFS4ERR_NOENT will be returned.  If createdir has a value of
        TRUE and no named attribute directory exists, one is created.
        The creation of a named attribute directory assumes that
        the server has implemented named attribute support in this
        fashion and is not required to do so by this definition.
      </t>

    </section>
    <section toc="exclude" anchor="OP_OPENATTR_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        If the server does not support named attributes for the current
        filehandle, an error of NFS4ERR_NOTSUPP will be returned to
        the client.
      </t>

    </section>
  </section>
  <section anchor="OP_OPEN_CONFIRM" title="Operation 20: OPEN_CONFIRM - Confirm Open">

    <section toc="exclude" anchor="OP_OPEN_CONFIRM_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh), seqid, stateid -> stateid
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_OPEN_CONFIRM_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct OPEN_CONFIRM4args {
        /* CURRENT_FH: opened file */
        stateid4        open_stateid;
        seqid4          seqid;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_OPEN_CONFIRM_RESULT" title="RESULT">

<figure>
 <artwork>
struct OPEN_CONFIRM4resok {
        stateid4        open_stateid;
};

union OPEN_CONFIRM4res switch (nfsstat4 status) {
 case NFS4_OK:
         OPEN_CONFIRM4resok     resok4;
 default:
         void;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_OPEN_CONFIRM_DESCRIPTION" title="DESCRIPTION">

      <t>
        This operation is used to confirm the sequence id usage
        for the first time that an open-owner is used by a client.
        The stateid returned from the OPEN operation is used as the
        argument for this operation along with the next sequence id for
        the open-owner.  The sequence id passed to the OPEN_CONFIRM
        must be 1 (one) greater than the seqid passed to the OPEN
        operation (<xref target='ss:fl:stateids' />).
        If the server receives an unexpected sequence id with respect
        to the original OPEN, then the server assumes that the client
        will not confirm the original OPEN and all state associated
        with the original OPEN is released by the server.
      </t>

      <t>
        On success, the current filehandle retains its value.
      </t>

    </section>
    <section toc="exclude" anchor="OP_OPEN_CONFIRM_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        A given client might generate many open_owner4 data structures
        for a given client ID.  The client will periodically either
        dispose of its open_owner4s or stop using them for indefinite
        periods of time.  The latter situation is why the NFSv4
        protocol does not have an explicit operation to exit an
        open_owner4: such an operation is of no use in that situation.
        Instead, to avoid unbounded memory use, the server needs to
        implement a strategy for disposing of open_owner4s that have
        no current open state for any files and
        have not been used recently.  The time period used to determine
        when to dispose of open_owner4s is an implementation choice.
        The time period should certainly be no less than the lease
        time plus any grace period the server wishes to implement
        beyond a lease time.  The OPEN_CONFIRM operation allows the
        server to safely dispose of unused open_owner4 data structures.
      </t>

      <t>
        In the case that a client issues an OPEN operation and the
        server no longer has a record of the open_owner4, the server
        needs to ensure that this is a new OPEN and not a replay
        or retransmission.
      </t>

      <t>
        Servers MUST NOT require confirmation on OPENs that grant
        delegations or are doing reclaim operations.  See 
        <xref target="ss:fl:open_conf" />
        for details.  The server can easily avoid
        this by noting whether it has disposed of one open_owner4 for
        the given client ID.  If the server does not support delegation,
        it might simply maintain a single bit that notes whether any
        open_owner4 (for any client) has been disposed of.
      </t>

      <t>
        The server must hold unconfirmed OPEN state until one of
        three events occurs.  First, the client sends an OPEN_CONFIRM
        request with the appropriate sequence id and stateid within
        the lease period.  In this case, the OPEN state on the
        server goes to confirmed, and the open_owner4 on the server
        is fully established.
      </t>

      <t>
        Second, the client sends another OPEN request with a sequence
        id that is incorrect for the open_owner4 (out of sequence).
        In this case, the server assumes the second OPEN request is
        valid and the first one is a replay.  The server cancels
        the OPEN state of the first OPEN request, establishes an
        unconfirmed OPEN state for the second OPEN request, and
        responds to the second OPEN request with an indication that
        an OPEN_CONFIRM is needed.  The process then repeats itself.
        While there is a potential for a denial-of-service attack on
        the client, it is mitigated if the client and server require
        the use of a security flavor based on Kerberos V5
        or some other flavor that uses cryptography.
      </t>

      <t>
        What if the server is in the unconfirmed OPEN state for a given
        open_owner4, and it receives an operation on the open_owner4
        that has a stateid but the operation is not OPEN, or it is
        OPEN_CONFIRM but with the wrong stateid?  Then, even if the
        seqid is correct, the server returns NFS4ERR_BAD_STATEID,
        because the server assumes the operation is a replay: if the
        server has no established OPEN state, then there is no way,
        for example, a LOCK operation could be valid.
      </t>

      <t>
        Third, neither of the two aforementioned events occurs for the
        open_owner4 within the lease period.  In this case, the OPEN
        state is canceled and disposal of the open_owner4 can occur.
      </t>

    </section>
  </section>
  <section anchor="OP_OPEN_DOWNGRADE" title="Operation 21: OPEN_DOWNGRADE - Reduce Open File Access">

    <section toc="exclude" anchor="OP_OPEN_DOWNGRADE_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh), stateid, seqid, access, deny -> stateid
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_OPEN_DOWNGRADE_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct OPEN_DOWNGRADE4args {
        /* CURRENT_FH: opened file */
        stateid4        open_stateid;
        seqid4          seqid;
        uint32_t        share_access;
        uint32_t        share_deny;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_OPEN_DOWNGRADE_RESULT" title="RESULT">

<figure>
 <artwork>
struct OPEN_DOWNGRADE4resok {
        stateid4        open_stateid;
};

union OPEN_DOWNGRADE4res switch (nfsstat4 status) {
 case NFS4_OK:
         OPEN_DOWNGRADE4resok    resok4;
 default:
         void;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_OPEN_DOWNGRADE_DESCRIPTION" title="DESCRIPTION">

      <t>
        This operation is used to adjust the share_access and
        share_deny bits for a given open.  This is necessary when
        a given open-owner opens the same file multiple times with
        different share_access and share_deny flags.  In this
        situation, a close of one of the opens may change the
        appropriate share_access and share_deny flags to remove bits
        associated with opens no longer in effect.
      </t>

      <t>
        The share_access and share_deny bits specified in this
        operation replace the current ones for the specified open file.
        The share_access and share_deny bits specified must be exactly
        equal to the union of the share_access and share_deny bits
        specified for some subset of the OPENs in effect for the current
        open-owner on the current file.  If that constraint is not
        respected, the error NFS4ERR_INVAL should be returned.
        Since share_access and share_deny bits are subsets of those
        already granted, it is not possible for this request to be
        denied because of conflicting share reservations.
      </t>

      <t>
        As the OPEN_DOWNGRADE may change a file to be not-open-for-write
        and a write byte-range lock might be held, the server may have to
        reject the OPEN_DOWNGRADE with an NFS4ERR_LOCKS_HELD.
      </t>

      <t>
        On success, the current filehandle retains its value.
      </t>

    </section>
  </section>
  <section anchor="OP_PUTFH" title="Operation 22: PUTFH - Set Current Filehandle">

    <section toc="exclude" anchor="OP_PUTFH_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  filehandle -> (cfh)
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_PUTFH_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct PUTFH4args {
        nfs_fh4         object;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_PUTFH_RESULT" title="RESULT">

<figure>
 <artwork>
struct PUTFH4res {
        /* CURRENT_FH: */
        nfsstat4        status;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_PUTFH_DESCRIPTION" title="DESCRIPTION">

      <t>
        PUTFH replaces the current filehandle with the filehandle provided
        as an argument.
      </t>

      <t>
        If the security mechanism used by the requester does not meet
        the requirements of the filehandle provided to this operation,
        the server MUST return NFS4ERR_WRONGSEC.
      </t>
      <t>
        See <xref target="current_filehandle"/> for more details on the
        current filehandle.
      </t>
    </section>
    <section toc="exclude" anchor="OP_PUTFH_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        PUTFH is commonly used as the first operator in an NFS request
        to set the context for operations that follow it.
      </t>

    </section>
  </section>
  <section anchor="OP_PUTPUBFH" title="Operation 23: PUTPUBFH - Set Public Filehandle">

    <section toc="exclude" anchor="OP_PUTPUBFH_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  - -> (cfh)
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_PUTPUBFH_ARGUMENT" title="ARGUMENT">

      <figure>
        <artwork>
  void;
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_PUTPUBFH_RESULT" title="RESULT">

<figure>
 <artwork>
struct PUTPUBFH4res {
        /* CURRENT_FH: public fh */
        nfsstat4        status;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_PUTPUBFH_DESCRIPTION" title="DESCRIPTION">

      <t>
        PUTPUBFH replaces the current filehandle with the filehandle that
        represents the public filehandle of the server's namespace.
        This filehandle may be different from the root filehandle,
        which may be associated with some other directory on the
        server.
      </t>

      <t>
        The public filehandle concept was introduced in
        <xref target="RFC2054" />, <xref target="RFC2055" />, and
        <xref target="RFC2224" />.  The intent for NFSv4 is that
        the public filehandle (represented by the PUTPUBFH operation)
        be used as a method of providing compatibility with the WebNFS server
        of NFSv2 and NFSv3.
      </t>

      <t>
        The public filehandle and the root filehandle (represented
        by the PUTROOTFH operation) should be equivalent.  If the
        public and root filehandles are not equivalent, then the
        public filehandle MUST be a descendant of the root filehandle.
      </t>

    </section>
    <section toc="exclude" anchor="OP_PUTPUBFH_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        PUTPUBFH is used as the first operator in an NFS request to set the
        context for operations that follow it.
      </t>

      <t>
        With the NFSv2 and NFSv3 public filehandle, the client is
        able to specify whether the pathname provided in the LOOKUP
        should be evaluated as either an absolute path relative
        to the server's root or relative to the public filehandle.
        <xref target="RFC2224" /> contains further discussion of the
        functionality.
        With NFSv4, that type of specification is not directly
        available in the LOOKUP operation.  The reason for this is
        because the component separators needed to specify absolute
        versus relative are not allowed in NFSv4.  Therefore, the
        client is responsible for constructing its request such that
        either PUTROOTFH or PUTPUBFH is used to signify absolute or
        relative evaluation of an NFS URL, respectively.
      </t>

      <t>
        Note that there are warnings mentioned in <xref target="RFC2224" /> with
        respect to the use of absolute evaluation and the restrictions
        the server may place on that evaluation with respect to how
        much of its namespace has been made available.  These same
        warnings apply to NFSv4.  It is likely, therefore,
        that because of server implementation details an NFSv3
        absolute public filehandle lookup may behave differently
        than an NFSv4 absolute resolution.
      </t>

      <t>
        There is a form of security negotiation as described
        in <xref target="RFC2755" /> that uses the public filehandle as a
        method of employing the Simple and Protected GSS-API
        Negotiation Mechanism (SNEGO) <xref target="RFC4178" />.  This
        method is not available with NFSv4, as filehandles are not
        overloaded with special meaning and therefore do not provide the
        same framework as NFSv2 and NFSv3.  Clients should therefore use
        the security negotiation mechanisms described in this RFC.
      </t>

    </section>
  </section>
  <section anchor="OP_PUTROOTFH" title="Operation 24: PUTROOTFH - Set Root Filehandle">

    <section toc="exclude" anchor="OP_PUTROOTFH_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  - -> (cfh)
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_PUTROOTFH_ARGUMENT" title="ARGUMENT">

      <figure>
        <artwork>
  void;
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_PUTROOTFH_RESULT" title="RESULT">

<figure>
 <artwork>
struct PUTROOTFH4res {
        /* CURRENT_FH: root fh */
        nfsstat4        status;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_PUTROOTFH_DESCRIPTION" title="DESCRIPTION">

      <t>
        PUTROOTFH replaces the current filehandle with the filehandle that
        represents the root of the server's namespace.  From this
        filehandle, a LOOKUP operation can locate any other filehandle
        on the server. This filehandle may be different from the
        public filehandle, which may be associated with some other
        directory on the server.
      </t>
      <t>
        See <xref target="current_filehandle"/> for more details on the
        current filehandle.
      </t>
    </section>
    <section toc="exclude" anchor="OP_PUTROOTFH_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        PUTROOTFH is commonly used as the first operator in an NFS request
        to set the context for operations that follow it.
      </t>

    </section>
  </section>
  <section anchor="OP_READ" title="Operation 25: READ - Read from File">

    <section toc="exclude" anchor="OP_READ_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh), stateid, offset, count -> eof, data
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_READ_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct READ4args {
        /* CURRENT_FH: file */
        stateid4        stateid;
        offset4         offset;
        count4          count;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_READ_RESULT" title="RESULT">

<figure>
 <artwork>
struct READ4resok {
        bool            eof;
        opaque          data&lt;>;
};

union READ4res switch (nfsstat4 status) {
 case NFS4_OK:
         READ4resok     resok4;
 default:
         void;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_READ_DESCRIPTION" title="DESCRIPTION">

      <t>
        The READ operation reads data from the regular file identified
        by the current filehandle.
      </t>

      <t>
        The client provides an offset of where the READ is to start
        and a count of how many bytes are to be read.  An offset
        of 0 (zero) means to read data starting at the beginning of
        the file.  If the offset is greater than or equal to the size of
        the file, the status, NFS4_OK, is returned with a data length
        set to 0 (zero), and eof is set to TRUE.  The READ is subject
        to access permissions checking.
      </t>

      <t>
        If the client specifies a count value of 0 (zero), the READ
        succeeds and returns 0 (zero) bytes of data (subject to
        access permissions checking).  The server may choose to
        return fewer bytes than specified by the client.  The client
        needs to check for this condition and handle the condition
        appropriately.
      </t>

      <t>
        The stateid value for a READ request represents a value
        returned from a previous byte-range lock or share reservation
        request, or the stateid associated with a delegation.
        The stateid is used by the server to verify that
        the associated share reservation and any byte-range locks are
        still valid and to update lease timeouts for the client.
      </t>

      <t>
        If the READ ended at the end-of-file (formally, in a correctly
        formed READ request, if offset + count is equal to the size of
        the file), or the READ request extends beyond the size of the
        file (if offset + count is greater than the size of the file),
        eof is returned as TRUE; otherwise, it is FALSE.  A successful
        READ of an empty file will always return eof as TRUE.
      </t>

      <t>
        If the current filehandle is not a regular file, an error
        will be returned to the client.  In the case where the current
        filehandle represents a directory, NFS4ERR_ISDIR is returned;
        otherwise, NFS4ERR_INVAL is returned.
      </t>

      <t>
        For a READ using the special anonymous stateid, the server
        MAY allow the READ to be serviced subject to mandatory file
        locks or the current share_deny modes for the file.  For a
        READ using the special READ bypass stateid, the server MAY
        allow READ operations to bypass locking checks at the server.
      </t>

      <t>
        On success, the current filehandle retains its value.
      </t>

    </section>
    <section toc="exclude" anchor="OP_READ_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        If the server returns a "short read" (i.e., less data than requested
        and eof is set to FALSE), the client should send another READ to get
        the remaining data.  A server may return less data than requested
        under several circumstances.  The file may have been truncated by
        another client or perhaps on the server itself, changing the file
        size from what the requesting client believes to be the case.  This
        would reduce the actual amount of data available to the client.  It
        is possible that the server reduces the transfer size and so returns a
        short read result.  Server resource exhaustion may also result in a
        short read.
      </t>

      <t>
        If mandatory byte-range locking is in effect for the file, and if the
        byte range corresponding to the data to be read from the file is
        WRITE_LT locked by an owner not associated with the stateid, the
        server will return the NFS4ERR_LOCKED error.  The client should try
        to get the appropriate READ_LT via the LOCK operation before
        re&nbhy;attempting the READ.  When the READ completes, the client
        should release the byte-range lock via LOCKU.
      </t>

      <t>
        If another client has an OPEN_DELEGATE_WRITE delegation for the file
        being read, the delegation must be recalled, and the operation cannot
        proceed until that delegation is returned or revoked.  Except where
        this happens very quickly, one or more NFS4ERR_DELAY errors will be
        returned to requests made while the delegation remains outstanding.
        Normally, delegations will not be recalled as a result of a READ
        operation, since the recall will occur as a result of an earlier OPEN.
        However, since it is possible for a READ to be done with a special
        stateid, the server needs to check for this case even though the
        client should have done an OPEN previously.
      </t>


    </section>
  </section>
  <section anchor="OP_READDIR" title="Operation 26: READDIR - Read Directory">

    <section toc="exclude" anchor="OP_READDIR_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh), cookie, cookieverf, dircount, maxcount, attr_request ->
  cookieverf { cookie, name, attrs }
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_READDIR_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct READDIR4args {
        /* CURRENT_FH: directory */
        nfs_cookie4     cookie;
        verifier4       cookieverf;
        count4          dircount;
        count4          maxcount;
        bitmap4         attr_request;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_READDIR_RESULT" title="RESULT">

<figure>
 <artwork>
struct entry4 {
        nfs_cookie4     cookie;
        component4      name;
        fattr4          attrs;
        entry4          *nextentry;
};

struct dirlist4 {
        entry4          *entries;
        bool            eof;
};

struct READDIR4resok {
        verifier4       cookieverf;
        dirlist4        reply;
};


union READDIR4res switch (nfsstat4 status) {
 case NFS4_OK:
         READDIR4resok  resok4;
 default:
         void;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_READDIR_DESCRIPTION" title="DESCRIPTION">

      <t>
        The READDIR operation retrieves a variable number of entries
        from a file system directory and for each entry returns
        attributes that were requested by the client, along with
        information to allow the client to request additional directory
        entries in a subsequent READDIR.
      </t>

      <t>
        The arguments contain a cookie value that represents where the
        READDIR should start within the directory.  A value of 0 (zero)
        for the cookie is used to start reading at the beginning of
        the directory.  For subsequent READDIR requests, the client
        specifies a cookie value that is provided by the server in
        a previous READDIR request.
      </t>

      <t>
        The cookieverf value should be set to 0 (zero) when the cookie
        value is 0 (zero) (first directory read).  On subsequent
        requests, it should be a cookieverf as returned by the server.
        The cookieverf must match that returned by the READDIR in
        which the cookie was acquired.  If the server determines
        that the cookieverf is no longer valid for the directory,
        the error NFS4ERR_NOT_SAME must be returned.
      </t>

      <t>
        The dircount portion of the argument is a hint of the maximum
        number of bytes of directory information that should be
        returned.  This value represents the length of the names of
        the directory entries and the cookie value for these entries.
        This length represents the XDR encoding of the data (names and
        cookies) and not the length in the native format of the server.
      </t>

      <t>
        The maxcount value of the argument is the maximum number of
        bytes for the result.  This maximum size represents all of
        the data being returned within the READDIR4resok structure and
        includes the XDR overhead.  The server may return less data.
        If the server is unable to return a single directory entry
        within the maxcount limit, the error NFS4ERR_TOOSMALL will
        be returned to the client.
      </t>

      <t>
        Finally, attr_request represents the list of attributes to
        be returned for each directory entry supplied by the server.
      </t>

      <t>
        On successful return, the server's response will provide a
        list of directory entries.  Each of these entries contains the
        name of the directory entry, a cookie value for that entry,
        and the associated attributes as requested.  The "eof" flag has
        a value of TRUE if there are no more entries in the directory.
      </t>

      <t>
        The cookie value is only meaningful to the server and is
        used as a "bookmark" for the directory entry.  As mentioned,
        this cookie is used by the client for subsequent READDIR
        operations so that it may continue reading a directory.
        The cookie is similar in concept to a READ offset but should
        not be interpreted as such by the client.  The server SHOULD
        try to accept cookie values issued with READDIR responses
        even if the directory has been modified between the READDIR
        calls but MAY return NFS4ERR_NOT_VALID if this is not
        possible, as might be the case if the server has rebooted
        in the interim.
      </t>

      <t>
        In some cases, the server may encounter an error while
        obtaining the attributes for a directory entry.  Instead of
        returning an error for the entire READDIR operation, the
        server can instead return the attribute 'fattr4_rdattr_error'.
        With this, the server is able to communicate the failure to
        the client and not fail the entire operation in the instance of
        what might be a transient failure.  Obviously, the client must
        request the fattr4_rdattr_error attribute for this method to
        work properly.  If the client does not request the attribute,
        the server has no choice but to return failure for the entire
        READDIR operation.
      </t>

      <t>
        For some file system environments, the directory entries "." and
        ".."  have special meaning, and in other environments, they
        may not.  If the server supports these special entries within
        a directory, they should not be returned to the client as part
        of the READDIR response.  To enable some client environments,
        the cookie values of 0, 1, and 2 are to be considered reserved.
        Note that the UNIX client will use these values when combining
        the server's response and local representations to enable a
        fully formed UNIX directory presentation to the application.
      </t>

      <t>
        For READDIR arguments, cookie values of 1 and 2 SHOULD NOT
        be used, and for READDIR results, cookie values of 0, 1, and
        2 MUST NOT be returned.
      </t>

      <t>
        On success, the current filehandle retains its value.
      </t>

    </section>
    <section toc="exclude" anchor="OP_READDIR_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        The server's file system directory representations can differ
        greatly.  A client's programming interfaces may also be bound
        to the local operating environment in a way that does not
        translate well into the NFS protocol.  Therefore, the
        dircount and maxcount fields are provided to allow
        the client the ability to provide guidelines to the server.
        If the client is aggressive about attribute collection during
        a READDIR, the server has an idea of how to limit the encoded
        response.  The dircount field provides a hint on the number of
        entries based solely on the names of the directory entries.
        Since it is a hint, it may be possible that a dircount value
        is zero.  In this case, the server is free to ignore the
        dircount value and return directory information based on the
        specified maxcount value.
      </t>

      <t>
        As there is no way for the client to indicate that a cookie
        value, once received, will not be subsequently used, server
        implementations should avoid schemes that allocate memory
        corresponding to a returned cookie. Such allocation can be
        avoided if the server bases cookie values on a value such
        as the offset within the directory where the scan is to be
        resumed.
      </t>

      <t>
        Cookies generated by such techniques should be designed to
        remain valid despite modification of the associated directory.
        If a server were to invalidate a cookie because of a directory
        modification, READDIRs of large directories might never
        finish.
      </t>

      <t>
        If a directory is deleted after the client has carried out
        one or more READDIR operations on the directory, the cookies
        returned will become invalid; however, the server does not need
        to be concerned, as the directory filehandle used previously
        would have become stale and would be reported as such on
        subsequent READDIR operations.  The server would not need
        to check the cookie verifier in this case.
      </t>

      <t>
        However, certain reorganization operations on a directory
        (including directory compaction) may invalidate READDIR
        cookies previously given out.  When such a situation occurs,
        the server should modify the cookie verifier so as to disallow
        the use of cookies that would otherwise no longer be valid.
      </t>

      <t>
        The cookieverf may be used by the server to help manage
        cookie values that may become stale.  It should be a rare
        occurrence that a server is unable to continue properly
        reading a directory with the provided cookie/cookieverf pair.
        The server should make every effort to avoid this condition
        since the application at the client may not be able to properly
        handle this type of failure.
      </t>

      <t>
        The use of the cookieverf will also protect the client from
        using READDIR cookie values that may be stale.  For example,
        if the file system has been migrated, the server may or may
        not be able to use the same cookie values to service READDIR
        as the previous server used.  With the client providing the
        cookieverf, the server is able to provide the appropriate
        response to the client.  This prevents the case where the
        server may accept a cookie value but the underlying directory
        has changed and the response is invalid from the client's
        context of its previous READDIR.
      </t>

      <t>
        Since some servers will not be returning "." and ".." entries
        as has been done with previous versions of the NFS protocol,
        the client that requires these entries be present in READDIR
        responses must fabricate them.
      </t>

    </section>
  </section>
  <section anchor="OP_READLINK" title="Operation 27: READLINK - Read Symbolic Link">

    <section toc="exclude" anchor="OP_READLINK_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh) -> linktext
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_READLINK_ARGUMENT" title="ARGUMENT">

      <figure>
        <artwork>
  /* CURRENT_FH: symlink */
  void;
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_READLINK_RESULT" title="RESULT">

<figure>
 <artwork>
struct READLINK4resok {
        linktext4       link;
};

union READLINK4res switch (nfsstat4 status) {
 case NFS4_OK:
         READLINK4resok resok4;
 default:
         void;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_READLINK_DESCRIPTION" title="DESCRIPTION">

      <t>
        READLINK reads the data associated with a symbolic link.
        The data is a UTF-8 string that is opaque to the server.
        That is, whether created by an NFS client or created locally
        on the server, the data in a symbolic link is not interpreted
        when created but is simply stored.
      </t>

      <t>
        On success, the current filehandle retains its value.
      </t>

    </section>
    <section toc="exclude" anchor="OP_READLINK_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        A symbolic link is nominally a pointer to another file.
        The data is not necessarily interpreted by the server; it is just
        stored in the file.  It is possible for a client implementation
        to store a pathname that is not meaningful to the server
        operating system in a symbolic link.  A READLINK operation
        returns the data to the client for interpretation. If different
        implementations want to share access to symbolic links,
        then they must agree on the interpretation of the data in
        the symbolic link.
      </t>

      <t>
        The READLINK operation is only allowed on objects of type
        NF4LNK.  The server should return the error NFS4ERR_INVAL
        if the object is not of type NF4LNK.
      </t>

    </section>
  </section>
  <section anchor="OP_REMOVE" title="Operation 28: REMOVE - Remove File System Object">

    <section toc="exclude" anchor="OP_REMOVE_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh), filename -> change_info
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_REMOVE_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct REMOVE4args {
        /* CURRENT_FH: directory */
        component4      target;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_REMOVE_RESULT" title="RESULT">

<figure>
 <artwork>
struct REMOVE4resok {
        change_info4    cinfo;
};

union REMOVE4res switch (nfsstat4 status) {
 case NFS4_OK:
         REMOVE4resok   resok4;
 default:
         void;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_REMOVE_DESCRIPTION" title="DESCRIPTION">

      <t>
        The REMOVE operation removes (deletes) a directory entry
        named by filename from the directory corresponding to the
        current filehandle.  If the entry in the directory was the
        last reference to the corresponding file system object, the
        object may be destroyed.
      </t>

      <t>
        For the directory where the filename was removed, the server
        returns change_info4 information in cinfo.  With the atomic
        field of the change_info4 struct, the server will indicate
        if the before and after change attributes were obtained
        atomically with respect to the removal.
      </t>

      <t>
        If the target is of zero length, NFS4ERR_INVAL will
        be returned.  The target is also subject to the normal
        UTF-8, character support, and name checks.  See 
        <xref target="ss:i18n:utf8_err" />
        for further discussion.
      </t>

      <t>
        On success, the current filehandle retains its value.
      </t>

    </section>
    <section toc="exclude" anchor="OP_REMOVE_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        NFSv3 required a different operator -- RMDIR -- for
        directory removal, and REMOVE for non-directory removal. This
        allowed clients to skip checking the file type when being
        passed a non-directory delete system call
        (e.g., unlink() <xref target="unlink" /> in POSIX) to
        remove a directory, as well as the converse
        (e.g., a rmdir() on a non&nbhy;directory), because they knew the
        server would check the file type.  NFSv4 REMOVE can
        be used to delete any directory entry, independent of its file
        type. The implementer of an NFSv4 client's entry
        points from the unlink() and rmdir() system calls should
        first check the file type against the types the system call
        is allowed to remove before issuing a REMOVE. Alternatively,
        the implementer can produce a COMPOUND call that includes
        a LOOKUP/VERIFY sequence to verify the file type before a
        REMOVE operation in the same COMPOUND call.
      </t>

      <t>
        The concept of last reference is server specific.  However,
        if the numlinks field in the previous attributes of the object
        had the value 1, the client should not rely on referring to
        the object via a filehandle.  Likewise, the client should
        not rely on the resources (disk space, directory entry,
        and so on) formerly associated with the object becoming
        immediately available.  Thus, if a client needs to be able
        to continue to access a file after using REMOVE to remove it,
        the client should take steps to make sure that the file will
        still be accessible.  The usual mechanism used is to RENAME
        the file from its old name to a new hidden name.
      </t>

      <t>
        If the server finds that the file is still open when the
        REMOVE arrives:

        <list style='symbols'>
          <t>
            The server SHOULD NOT delete the file's directory entry
            if the file was opened with OPEN4_SHARE_DENY_WRITE or
            OPEN4_SHARE_DENY_BOTH.
          </t>

          <t>
            If the file was not opened with OPEN4_SHARE_DENY_WRITE or
            OPEN4_SHARE_DENY_BOTH, the server SHOULD delete the file's
            directory entry.  However, until the last CLOSE of the file,
            the server MAY continue to allow access to the file via
            its filehandle.
          </t>
        </list>
      </t>

    </section>
  </section>
  <section anchor="OP_RENAME" title="Operation 29: RENAME - Rename Directory Entry">

    <section toc="exclude" anchor="OP_RENAME_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (sfh), oldname, (cfh), newname -> source_cinfo, target_cinfo
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_RENAME_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct RENAME4args {
        /* SAVED_FH: source directory */
        component4      oldname;
        /* CURRENT_FH: target directory */
        component4      newname;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_RENAME_RESULT" title="RESULT">

<figure>
 <artwork>
struct RENAME4resok {
        change_info4    source_cinfo;
        change_info4    target_cinfo;
};

union RENAME4res switch (nfsstat4 status) {
 case NFS4_OK:
         RENAME4resok    resok4;
 default:
         void;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_RENAME_DESCRIPTION" title="DESCRIPTION">

      <t>
        The RENAME operation renames the object identified by
        oldname in the source directory corresponding to the saved
        filehandle, as set by the SAVEFH operation, to newname in
        the target directory corresponding to the current filehandle.
        The operation is required to be atomic to the client.  Source
        and target directories must reside on the same file system on
        the server.  On success, the current filehandle will continue
        to be the target directory.
      </t>

      <t>
        If the target directory already contains an entry with the
        name newname, the source object must be compatible with
        the target: either both are non-directories, or both are
        directories, and the target must be empty.  If compatible,
        the existing target is removed before the rename occurs (see
        <xref target="OP_REMOVE" /> for client and server
        actions whenever a target is removed).  If they are not
        compatible or if the target is a directory but not empty,
        the server will return the error NFS4ERR_EXIST.
      </t>

      <t>
        If oldname and newname both refer to the same file (they might
        be hard links of each other), then RENAME should perform no
        action and return success.
      </t>

      <t>
        For both directories involved in the RENAME, the server
        returns change_info4 information.  With the atomic field
        of the change_info4 struct, the server will indicate if the
        before and after change attributes were obtained atomically
        with respect to the rename.
      </t>

      <t>
        If the oldname refers to a named attribute and the saved and
        current filehandles refer to the named attribute directories
        of different file system objects,
        the server will return NFS4ERR_XDEV, just as if the saved
        and current filehandles represented directories on different
        file systems.
      </t>

      <t>
        If the oldname or newname is of zero length, NFS4ERR_INVAL will
        be returned.  The oldname and newname are also subject to the 
        normal UTF-8, character support, and name checks.  See 
        <xref target="ss:i18n:utf8_err" />
        for further discussion.
      </t>

    </section>
    <section toc="exclude" anchor="OP_RENAME_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        The RENAME operation must be atomic to the client.  The
        statement "source and target directories must reside on the
        same file system on the server" means that the fsid fields in
        the attributes for the directories are the same. If they reside
        on different file systems, the error NFS4ERR_XDEV is returned.
      </t>

      <t>
        Based on the value of the fh_expire_type attribute for the
        object, the filehandle may or may not expire on a RENAME.
        However, server implementers are strongly encouraged to
        attempt to keep filehandles from expiring in this fashion.
      </t>

      <t>
        On some servers, the filenames "." and ".." are illegal
        as either oldname or newname and will result in the error
        NFS4ERR_BADNAME.  In addition, on many servers the case of
        oldname or newname being an alias for the source directory
        will be checked for.  Such servers will return the error
        NFS4ERR_INVAL in these cases.
      </t>

      <t>
        If either of the source or target filehandles are not
        directories, the server will return NFS4ERR_NOTDIR.
      </t>

    </section>
  </section>
  <section anchor="OP_RENEW" title="Operation 30: RENEW - Renew a Lease">

    <section toc="exclude" anchor="OP_RENEW_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  clientid -> ()
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_RENEW_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct RENEW4args {
        clientid4       clientid;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_RENEW_RESULT" title="RESULT">

<figure>
 <artwork>
struct RENEW4res {
        nfsstat4        status;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_RENEW_DESCRIPTION" title="DESCRIPTION">

      <t>
        The RENEW operation is used by the client to renew leases
        that it currently holds at a server.  In processing the
        RENEW request, the server renews all leases associated with
        the client.  The associated leases are determined by the
        clientid provided via the SETCLIENTID operation.
      </t>

    </section>
    <section toc="exclude" anchor="OP_RENEW_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        When the client holds delegations, it needs to use RENEW to
        detect when the server has determined that the callback path
        is down.  When the server has made such a determination, only
        the RENEW operation will renew the lease on delegations.
        If the server determines the callback path is down, it
        returns NFS4ERR_CB_PATH_DOWN.  Even though it returns
        NFS4ERR_CB_PATH_DOWN, the server MUST renew the lease on
        the byte-range locks and share reservations that the client has
        established on the server.  If for some reason the lock and
        share reservation lease cannot be renewed, then the server
        MUST return an error other than NFS4ERR_CB_PATH_DOWN, even
        if the callback path is also down.  In the event that
        the server has conditions such that it could return either
        NFS4ERR_CB_PATH_DOWN or NFS4ERR_LEASE_MOVED,
        NFS4ERR_LEASE_MOVED MUST be handled first.
      </t>

      <t>
        The client that issues RENEW MUST choose the principal,
        RPC security flavor, and, if applicable, GSS-API mechanism
        and service via one of the following algorithms:

        <list style='symbols'>
          <t>
            The client uses the same principal, RPC security flavor,
            and -- if the flavor was RPCSEC_GSS -- the same mechanism and
            service that were used when the client ID was established
            via SETCLIENTID_CONFIRM.
          </t>

          <t>
            The client uses any principal, RPC security flavor, mechanism,
            and service combination that currently has an OPEN file
            on the server.  That is, the same principal had a successful
            OPEN operation; the file is still open by that principal;
            and the flavor, mechanism, and service of RENEW match that
            of the previous OPEN.
          </t>
        </list>
      </t>

      <t>
        The server MUST reject a RENEW that does not use one of the
        aforementioned algorithms, with the error NFS4ERR_ACCESS.
      </t>

    </section>
  </section>
  <section anchor="OP_RESTOREFH" title="Operation 31: RESTOREFH - Restore Saved Filehandle">

    <section toc="exclude" anchor="OP_RESTOREFH_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (sfh) -> (cfh)
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_RESTOREFH_ARGUMENT" title="ARGUMENT">

      <figure>
        <artwork>
  /* SAVED_FH: */
  void;
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_RESTOREFH_RESULT" title="RESULT">

<figure>
 <artwork>
struct RESTOREFH4res {
        /* CURRENT_FH: value of saved fh */
        nfsstat4        status;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_RESTOREFH_DESCRIPTION" title="DESCRIPTION">

      <t>
        Set the current filehandle to the value in the saved
        filehandle.  If there is no saved filehandle, then return the
        error NFS4ERR_RESTOREFH.
      </t>

    </section>
    <section toc="exclude" anchor="OP_RESTOREFH_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        Operations like OPEN and LOOKUP use the current filehandle to
        represent a directory and replace it with a new filehandle.
        Assuming that the previous filehandle was saved with a SAVEFH
        operator, the previous filehandle can be restored as
        the current filehandle.  This is commonly used to obtain
        post-operation attributes for the directory, e.g.,
      </t>

      <figure>
        <artwork>
  PUTFH (directory filehandle)
  SAVEFH
  GETATTR attrbits     (pre-op dir attrs)
  CREATE optbits "foo" attrs
  GETATTR attrbits     (file attributes)
  RESTOREFH
  GETATTR attrbits     (post-op dir attrs)
        </artwork>
      </figure>

    </section>
  </section>
  <section anchor="OP_SAVEFH" title="Operation 32: SAVEFH - Save Current Filehandle">

    <section toc="exclude" anchor="OP_SAVEFH_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh) -> (sfh)
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_SAVEFH_ARGUMENT" title="ARGUMENT">

      <figure>
        <artwork>
  /* CURRENT_FH: */
  void;
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_SAVEFH_RESULT" title="RESULT">

<figure>
 <artwork>
struct SAVEFH4res {
        /* SAVED_FH: value of current fh */
        nfsstat4        status;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_SAVEFH_DESCRIPTION" title="DESCRIPTION">

      <t>
        Save the current filehandle.  If a previous filehandle was
        saved, then it is no longer accessible.  The saved filehandle
        can be restored as the current filehandle with the RESTOREFH
        operator.
      </t>

      <t>
        On success, the current filehandle retains its value.
      </t>

    </section>
    <section toc="exclude" anchor="OP_SAVEFH_IMPLEMENTATION" title="IMPLEMENTATION">

    </section>
  </section>
  <section anchor="OP_SECINFO" title="Operation 33: SECINFO - Obtain Available Security">

    <section toc="exclude" anchor="OP_SECINFO_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh), name -> { secinfo }
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_SECINFO_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct SECINFO4args {
        /* CURRENT_FH: directory */
        component4      name;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_SECINFO_RESULT" title="RESULT">

<figure>
 <artwork>
/*
 * From RFC 2203
 */
enum rpc_gss_svc_t {
        RPC_GSS_SVC_NONE        = 1,
        RPC_GSS_SVC_INTEGRITY   = 2,
        RPC_GSS_SVC_PRIVACY     = 3
};

struct rpcsec_gss_info {
        sec_oid4        oid;
        qop4            qop;
        rpc_gss_svc_t   service;
};

/* RPCSEC_GSS has a value of '6'.  See RFC 2203 */
union secinfo4 switch (uint32_t flavor) {
 case RPCSEC_GSS:
         rpcsec_gss_info        flavor_info;
 default:
         void;
};

typedef secinfo4 SECINFO4resok&lt;>;

union SECINFO4res switch (nfsstat4 status) {
 case NFS4_OK:
         SECINFO4resok resok4;
 default:
         void;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_SECINFO_DESCRIPTION" title="DESCRIPTION">

      <t>
        The SECINFO operation is used by the client to obtain a list
        of valid RPC authentication flavors for a specific directory
        filehandle, filename pair.  SECINFO should apply the same
        access methodology used for LOOKUP when evaluating the name.
        Therefore, if the requester does not have the appropriate
        access to perform a LOOKUP for the name, then SECINFO must
        behave the same way and return NFS4ERR_ACCESS.
      </t>

      <t>
        The result will contain an array that represents the security
        mechanisms available, with an order corresponding to the server's
        preferences, the most preferred being first in the array. The
        client is free to pick whatever security mechanism it both
        desires and supports, or to pick -- in the server's preference
        order -- the first one it supports.  The array entries are
        represented by the secinfo4 structure.  The field 'flavor'
        will contain a value of AUTH_NONE, AUTH_SYS (as defined in
        <xref target="RFC5531" />), or RPCSEC_GSS (as defined in
        <xref target="RFC2203" />).
      </t>

      <t>
        For the flavors AUTH_NONE and AUTH_SYS, no additional security
        information is returned.  For a return value of RPCSEC_GSS,
        a security triple is returned that contains the mechanism
        object id (as defined in <xref target="RFC2743" />), the quality
        of protection (as defined in <xref target="RFC2743" />), and the
        service type (as defined in <xref target="RFC2203" />).  It
        is possible for SECINFO to return multiple entries with
        flavor equal to RPCSEC_GSS, with different security triple values.
      </t>

      <t>
        On success, the current filehandle retains its value.
      </t>

      <t>
        If the name has a length of 0 (zero), or if the name does not obey
        the UTF-8 definition, the error NFS4ERR_INVAL will be returned.
      </t>

    </section>
    <section toc="exclude" anchor="OP_SECINFO_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        The SECINFO operation is expected to be used by the NFS
        client when the error value of NFS4ERR_WRONGSEC is returned
        from another NFS operation.  This signifies to the client
        that the server's security policy is different from what
        the client is currently using.  At this point, the client is
        expected to obtain a list of possible security flavors and
        choose what best suits its policies.
      </t>

      <t>
        As mentioned, the server's security policies will
        determine when a client request receives NFS4ERR_WRONGSEC.
        The operations that may receive this error are LINK,
        LOOKUP, LOOKUPP, OPEN, PUTFH, PUTPUBFH, PUTROOTFH, RENAME,
        RESTOREFH, and, indirectly, READDIR.  LINK and RENAME will only
        receive this error if the security used for the operation
        is inappropriate for the saved filehandle.  With the exception
        of READDIR, these operations represent the point at which
        the client can instantiate a filehandle into the
        current filehandle at the server.  The filehandle is either provided
        by the client (PUTFH, PUTPUBFH, PUTROOTFH) or generated as a
        result of a name-to-filehandle translation (LOOKUP and OPEN).
        RESTOREFH is different because the filehandle is a result of a
        previous SAVEFH.  Even though the filehandle, for RESTOREFH,
        might have previously passed the server's inspection for a
        security match, the server will check it again on RESTOREFH
        to ensure that the security policy has not changed.
      </t>

      <t>
        If the client wants to resolve an error return of
        NFS4ERR_WRONGSEC, the following will occur:

        <list style='symbols'>
          <t>
            For LOOKUP and OPEN, the client will use SECINFO with the
            same current filehandle and name as provided in the original
            LOOKUP or OPEN to enumerate the available security triples.
          </t>

          <t>
            For LINK, PUTFH, RENAME, and RESTOREFH, the client will
            use SECINFO and provide the parent directory filehandle and
            the object name that corresponds to the filehandle originally
            provided by the PUTFH or RESTOREFH, or, for LINK and RENAME,
            the SAVEFH.
          </t>

          <t>
            For LOOKUPP, PUTROOTFH, and PUTPUBFH, the client will be unable
            to use the SECINFO operation since SECINFO requires a
            current filehandle and none exist for these three operations.
            Therefore, the client must iterate through the security
            triples available at the client and re&nbhy;attempt the
            PUTROOTFH or PUTPUBFH operation. In the unfortunate event
            that none of the MANDATORY security triples are supported by
            the client and server, the client SHOULD try using others that
            support integrity. Failing that, the client can try using
            AUTH_NONE, but because such forms lack integrity checks,
            this puts the client at risk.  Nonetheless, the server
            SHOULD allow the client to use whatever security form the
            client requests and the server supports, since the risks
            of doing so are on the client.
          </t>
        </list>
      </t>

      <t>
        The READDIR operation will not directly return the
        NFS4ERR_WRONGSEC error.  However, if the READDIR request
        included a request for attributes, it is possible that the
        READDIR request's security triple does not match that of
        a directory entry.  If this is the case and the client has
        requested the rdattr_error attribute, the server will return
        the NFS4ERR_WRONGSEC error in rdattr_error for the entry.
      </t>

      <t>
        Note that a server MAY use the AUTH_NONE flavor to signify that
        the client is allowed to attempt to use authentication flavors
        that are not explicitly listed in the SECINFO results.
        Instead of using a listed flavor, the client might then,
        for instance, opt to use an otherwise unlisted RPCSEC_GSS
        mechanism instead of AUTH_NONE. It may wish to do so in order
        to meet an application requirement for data integrity or privacy.
        In choosing to use an unlisted flavor, the client SHOULD always
        be prepared to handle a failure by falling back to using AUTH_NONE
        or another listed flavor. It cannot assume that identity mapping
        is supported and should be prepared for the fact that its identity
        is squashed.
      </t>

      <t>
        See <xref target="sec:security" /> for a discussion
        on the recommendations for security flavors used by SECINFO.
      </t>

    </section>
  </section>
  <section anchor="OP_SETATTR" title="Operation 34: SETATTR - Set Attributes">

    <section toc="exclude" anchor="OP_SETATTR_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh), stateid, attrmask, attr_vals -> attrsset
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_SETATTR_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct SETATTR4args {
        /* CURRENT_FH: target object */
        stateid4        stateid;
        fattr4          obj_attributes;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_SETATTR_RESULT" title="RESULT">

<figure>
 <artwork>
struct SETATTR4res {
        nfsstat4        status;
        bitmap4         attrsset;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_SETATTR_DESCRIPTION" title="DESCRIPTION">

      <t>
        The SETATTR operation changes one or more of the attributes of
        a file system object.  The new attributes are specified with a
        bitmap and the attributes that follow the bitmap in bit order.
      </t>

      <t>
        The stateid argument for SETATTR is used to provide byte-range
        locking context that is necessary for SETATTR requests that
        set the size attribute.  Since setting the size attribute
        modifies the file's data, it has the same locking requirements
        as a corresponding WRITE.  Any SETATTR that sets the size
        attribute is incompatible with a share reservation that
        specifies OPEN4_SHARE_DENY_WRITE.  The area between the old end-of-file
        and the new end-of-file is considered to be modified just
        as would have been the case had the area in question been
        specified as the target of WRITE, for the purpose of checking
        conflicts with byte-range locks, for those cases in which a
        server is implementing mandatory byte-range locking behavior.
        A valid stateid SHOULD always be specified.  When the file
        size attribute is not set, the special anonymous stateid
        MAY be passed.
      </t>

      <t>
        On either success or failure of the operation, the server
        will return the attrsset bitmask to represent what (if any)
        attributes were successfully set.  The attrsset in the response
        is a subset of the bitmap4 that is part of the obj_attributes
        in the argument.
      </t>

      <t>
        On success, the current filehandle retains its value.
      </t>

    </section>
    <section toc="exclude" anchor="OP_SETATTR_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        If the request specifies the owner attribute to be set, the
        server SHOULD allow the operation to succeed if the current
        owner of the object matches the value specified in the request.
        Some servers may be implemented in such a way as to prohibit
        the setting of the owner attribute unless the requester has the
        privilege to do so.  If the server is lenient in this one
        case of matching owner values, the client implementation may
        be simplified in cases of creation of an object 
        (e.g., an exclusive create via OPEN) followed by a SETATTR.
      </t>

      <t>
        The file size attribute is used to request changes to the
        size of a file. A value of zero causes the file to
        be truncated, a value less than the current size of the
        file causes data from the new size to the end of the file to
        be discarded, and a size greater than the current size of
        the file causes logically zeroed data bytes to be added to
        the end of the file.  Servers are free to implement this
        using holes or actual zero data bytes. Clients should not
        make any assumptions regarding a server's implementation of
        this feature, beyond that the bytes returned will be zeroed.
        Servers MUST support extending the file size via SETATTR.
      </t>

      <t>
        SETATTR is not guaranteed atomic.  A failed SETATTR may
        partially change a file's attributes -- hence, the reason why
        the reply always includes the status and the list of attributes
        that were set.
      </t>

      <t>
        If the object whose attributes are being changed has a file
        delegation that is held by a client other than the one doing the
        SETATTR, the delegation(s) must be recalled, and the operation cannot
        proceed to actually change an attribute until each such delegation is
        returned or revoked.  In all cases in which delegations are recalled,
        the server is likely to return one or more NFS4ERR_DELAY errors while
        the delegation(s) remains outstanding, although it might not do that
        if the delegations are returned quickly.
      </t>

      <t>
        Changing the size of a file with SETATTR indirectly changes
        the time_modify and change attributes.  A client must account for
        this, as size changes can result in data deletion.
      </t>

      <t>
        The attributes time_access_set and time_modify_set are
        write-only attributes constructed as a switched union so the
        client can direct the server in setting the time values.
        If the switched union specifies SET_TO_CLIENT_TIME4, the
        client has provided an nfstime4 to be used for the operation.
        If the switch union does not specify SET_TO_CLIENT_TIME4, the
        server is to use its current time for the SETATTR operation.
      </t>

      <t>
        If server and client times differ, programs that compare
        client times to file times can break. A time maintenance
        protocol should be used to limit client/server time skew.
      </t>

      <t>
        Use of a COMPOUND containing a VERIFY operation specifying
        only the change attribute, immediately followed by a SETATTR,
        provides a means whereby a client may specify a request that
        emulates the functionality of the SETATTR guard mechanism of
        NFSv3.  Since the function of the guard mechanism
        is to avoid changes to the file attributes based on stale
        information, delays between checking of the guard condition
        and the setting of the attributes have the potential to
        compromise this function, as would the corresponding delay in
        the NFSv4 emulation.  Therefore, NFSv4 servers
        should take care to avoid such delays, to the degree possible,
        when executing such a request.
      </t>

      <t>
        If the server does not support an attribute as requested by
        the client, the server should return NFS4ERR_ATTRNOTSUPP.
      </t>

      <t>
        A mask of the attributes actually set is returned by SETATTR
        in all cases.  That mask MUST NOT include attribute bits not
        requested to be set by the client.  If the attribute masks in
        the request and reply are equal, the status field in the reply
        MUST be NFS4_OK.
      </t>

    </section>
  </section>
  <section anchor="OP_SETCLIENTID" title="Operation 35: SETCLIENTID - Negotiate Client ID">

    <section toc="exclude" anchor="OP_SETCLIENTID_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  client, callback, callback_ident -> clientid, setclientid_confirm
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_SETCLIENTID_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct SETCLIENTID4args {
        nfs_client_id4  client;
        cb_client4      callback;
        uint32_t        callback_ident;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_SETCLIENTID_RESULT" title="RESULT">

<figure>
 <artwork>
struct SETCLIENTID4resok {
        clientid4       clientid;
        verifier4       setclientid_confirm;
};

union SETCLIENTID4res switch (nfsstat4 status) {
 case NFS4_OK:
         SETCLIENTID4resok      resok4;
 case NFS4ERR_CLID_INUSE:
         clientaddr4    client_using;
 default:
         void;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_SETCLIENTID_DESCRIPTION" title="DESCRIPTION">

      <t>
        The client uses the SETCLIENTID operation to notify the server
        of its intention to use a particular client identifier,
        callback, and callback_ident for subsequent requests that
        entail creating lock, share reservation, and delegation
        state on the server.  Upon successful completion the server
        will return a shorthand client ID that, if confirmed via a
        separate step, will be used in subsequent file locking and
        file open requests. Confirmation of the client ID must be done
        via the SETCLIENTID_CONFIRM operation to return the client ID
        and setclientid_confirm values, as verifiers, to the server.
        Two verifiers are necessary because it is possible to use
        SETCLIENTID and SETCLIENTID_CONFIRM to modify the callback and
        callback_ident information but not the shorthand client ID.  In
        that event, the setclientid_confirm value is effectively the
        only verifier.
      </t>

      <t>
        The callback information provided in this operation will
        be used if the client is provided an open delegation at a
        future point.  Therefore, the client must correctly reflect
        the program and port numbers for the callback program at the
        time SETCLIENTID is used.
      </t>

      <t>
        The callback_ident value is used by the server on the callback.
        The client can leverage the callback_ident to eliminate the
        need for more than one callback RPC program number, while
        still being able to determine which server is initiating
        the callback.
      </t>

    </section>
    <section toc="exclude" anchor="OP_SETCLIENTID_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        To understand how to implement SETCLIENTID, make the following
        notations. Let:

        <list style='hanging'>
          <t hangText="x">
            be the value of the client.id subfield of the
            SETCLIENTID4args structure.
          </t>

          <t hangText="v">
            be the value of the client.verifier subfield of the
            SETCLIENTID4args structure.
          </t>

          <t hangText="c">
            be the value of the client ID field returned in the
            SETCLIENTID4resok structure.
          </t>

          <t hangText="k">
            represent the value combination of the callback and
            callback_ident fields of the SETCLIENTID4args structure.
          </t>

          <t hangText="s">
            be the setclientid_confirm value returned in the
            SETCLIENTID4resok structure.
          </t>

          <t hangText="{ v, x, c, k, s }">
            be a quintuple for a client record. A client
            record is confirmed if there has been a SETCLIENTID_CONFIRM
            operation to confirm it.  Otherwise, it is unconfirmed. An
            unconfirmed record is established by a SETCLIENTID call.
          </t>
        </list>
      </t>

      <t>
        Since SETCLIENTID is a non-idempotent operation, let us assume
        that the server is implementing the duplicate request cache (DRC).
      </t>

      <t>
        When the server gets a SETCLIENTID { v, x, k } request,
        it processes it in the following manner.

        <list style='symbols'>
          <t>
            It first looks up the request in the DRC. If there is a
            hit, it returns the result cached in the DRC.  The server
            does NOT remove client state (locks, shares, delegations),
            nor does it modify any recorded callback and callback_ident
            information for client { x }.
          <vspace blankLines='1' />
            For any DRC miss, the server takes the client ID string
            x, and searches for client records for x that the server
            may have recorded from previous SETCLIENTID calls. For
            any confirmed record with the same id string x, if the
            recorded principal does not match that of the
            SETCLIENTID call, then the server returns
            an NFS4ERR_CLID_INUSE error.
          <vspace blankLines='1' />
            For brevity of discussion, the remaining description of
            the processing assumes that there was a DRC miss, and
            that where the server has previously recorded a confirmed
            record for client x, the aforementioned principal check
            has successfully passed.
          </t>

          <t>
            The server checks if it has recorded a confirmed record for
            { v, x, c, l, s }, where l may or may not equal k. If so,
            and since the id verifier v of the request matches that
            which is confirmed and recorded, the server treats this
            as a probable callback information update and records an
            unconfirmed { v, x, c, k, t } and leaves the confirmed { v,
            x, c, l, s } in place, such that t&nbsp;!=&nbsp;s.
            It does not matter whether k equals l or not.  Any
            pre&nbhy;existing unconfirmed { v, x, c, *, * } is removed.
          <vspace blankLines='1' />
            The server returns { c, t }.  It is indeed returning the
            old clientid4 value c, because the client apparently only
            wants to update callback value k to value l.  It's possible
            this request is one from the Byzantine router that has
            stale callback information, but this is not a problem.
            The callback information update is only confirmed if
            followed up by a SETCLIENTID_CONFIRM { c, t }.
          <vspace blankLines='1' />
            The server awaits confirmation of k via SETCLIENTID_CONFIRM
            {&nbsp;c,&nbsp;t&nbsp;}.
          <vspace blankLines='1' />
            The server does NOT remove client (lock/share/delegation)
            state for x.
          </t>

          <t>
            The server has previously recorded a confirmed { u, x, c,
            l, s } record such that v != u, l may or may not equal k,
            and has not recorded any unconfirmed { *, x, *, *, * }
            record for x.  The server records an unconfirmed { v, x,
            d, k, t } (d != c, t != s).
          <vspace blankLines='1' />
            The server returns { d, t }.
          <vspace blankLines='1' />
            The server awaits confirmation of { d, k } via
            SETCLIENTID_CONFIRM { d, t }.
          <vspace blankLines='1' />
            The server does NOT remove client (lock/share/delegation)
            state for x.
          </t>

          <t>
            The server has previously recorded a confirmed { u, x, c,
            l, s } record such that v != u, l may or may not equal k,
            and recorded an unconfirmed { w, x, d, m, t } record such
            that c != d, t != s, m may or may not equal k, m may or may
            not equal l, and k may or may not equal l. Whether w == v
            or w != v makes no difference.  The server simply removes
            the unconfirmed { w, x, d, m, t } record and replaces it
            with an unconfirmed { v, x, e, k, r } record, such that e !=
            d, e != c, r != t, r != s.
          <vspace blankLines='1' />
            The server returns { e, r }.
          <vspace blankLines='1' />
            The server awaits confirmation of { e, k } via
            SETCLIENTID_CONFIRM { e, r }.
          <vspace blankLines='1' />
            The server does NOT remove client (lock/share/delegation)
            state for x.
          </t>

          <t>
            The server has no confirmed { *, x, *, *, * } for x. It
            may or may not have recorded an unconfirmed { u, x, c,
            l, s }, where l may or may not equal k, and u may or may
            not equal v.  Any unconfirmed record { u, x, c, l, * },
            regardless of whether u == v or l == k, is replaced with an
            unconfirmed record { v, x, d, k, t } where d != c, t != s.
          <vspace blankLines='1' />
            The server returns { d, t }.
          <vspace blankLines='1' />
            The server awaits confirmation of { d, k } via
            SETCLIENTID_CONFIRM { d, t }.  The server does NOT remove
            client (lock/share/delegation) state for x.
          </t>
        </list>
      </t>

      <t>
        The server generates the clientid and setclientid_confirm
        values and must take care to ensure that these values are
        extremely unlikely to ever be regenerated.
      </t>

    </section>
  </section>
  <section anchor="OP_SETCLIENTID_CONFIRM" title="Operation 36: SETCLIENTID_CONFIRM - Confirm Client ID">

    <section toc="exclude" anchor="OP_SETCLIENTID_CONFIRM_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  clientid, setclientid_confirm -> -
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_SETCLIENTID_CONFIRM_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct SETCLIENTID_CONFIRM4args {
        clientid4       clientid;
        verifier4       setclientid_confirm;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_SETCLIENTID_CONFIRM_RESULT" title="RESULT">

<figure>
 <artwork>
struct SETCLIENTID_CONFIRM4res {
        nfsstat4        status;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_SETCLIENTID_CONFIRM_DESCRIPTION" title="DESCRIPTION">

      <t>
        This operation is used by the client to confirm the results
        from a previous call to SETCLIENTID.  The client provides
        the server-supplied (from a SETCLIENTID response) client ID.
        The server responds with a simple status of success or failure.
      </t>

    </section>
    <section toc="exclude" anchor="OP_SETCLIENTID_CONFIRM_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        The client must use the SETCLIENTID_CONFIRM operation to
        confirm the following two distinct cases:

        <list style='symbols'>
          <t>
            The client's use of a new shorthand client identifier (as
            returned from the server in the response to SETCLIENTID),
            a new callback value (as specified in the arguments
            to SETCLIENTID), and a new callback_ident value (as
            specified in the arguments to SETCLIENTID).  The client's
            use of SETCLIENTID_CONFIRM in this case also confirms
            the removal of any of the client's previous relevant
            leased state. Relevant leased client state includes
            byte-range locks, share reservations, and -- where the
            server does not support the CLAIM_DELEGATE_PREV claim type --
            delegations.  If the server supports CLAIM_DELEGATE_PREV,
            then SETCLIENTID_CONFIRM MUST NOT remove delegations for
            this client; relevant leased client state would then just
            include byte-range locks and share reservations.
          </t>

          <t>
            The client's reuse of an old, previously confirmed
            shorthand client identifier; a new callback value;
            and a new callback_ident value.  The client's use of
            SETCLIENTID_CONFIRM in this case MUST NOT result in
            the removal of any previous leased state (locks, share
            reservations, and delegations).
          </t>
        </list>
      </t>

      <t>
        We use the same notation and definitions for v, x, c, k, s,
        and unconfirmed and confirmed client records as introduced in
        the description of the SETCLIENTID operation. The arguments
        to SETCLIENTID_CONFIRM are indicated by the notation { c, s
        }, where c is a value of type clientid4, and s is a value of
        type verifier4 corresponding to the setclientid_confirm field.
      </t>

      <t>
        As with SETCLIENTID, SETCLIENTID_CONFIRM is a non-idempotent
        operation, and we assume that the server is implementing the
        duplicate request cache (DRC).
      </t>

      <t>
        When the server gets a SETCLIENTID_CONFIRM { c, s } request,
        it processes it in the following manner.

        <list style='symbols'>
          <t>
            It first looks up the request in the DRC. If there is a hit,
            it returns the result cached in the DRC.  The server does
            not remove any relevant leased client state, nor does it
            modify any recorded callback and callback_ident information
            for client { x } as represented by the shorthand value c.
          </t>
        </list>
      </t>

      <t>
        For a DRC miss, the server checks for client records that match
        the shorthand value c.  The processing cases are as follows:

        <list style='symbols'>
          <t>
            The server has recorded an unconfirmed { v, x, c, k, s }
            record and a confirmed { v, x, c, l, t } record, such
            that s != t.  If the principals of the records do not
            match that of the SETCLIENTID_CONFIRM, the server returns
            NFS4ERR_CLID_INUSE, and no relevant leased client state
            is removed and no recorded callback and callback_ident
            information for client { x } is changed.  Otherwise, the
            confirmed { v, x, c, l, t } record is removed and the
            unconfirmed { v, x, c, k, s } is marked as confirmed,
            thereby modifying recorded and confirmed callback and
            callback_ident information for client { x }.
          <vspace blankLines='1' />
            The server does not remove any relevant leased client state.
          <vspace blankLines='1' />
            The server returns NFS4_OK.
          </t>

          <t>
            The server has not recorded an unconfirmed { v, x, c, *, * }
            and has recorded a confirmed { v, x, c, *, s }.  If the
            principals of the record and of SETCLIENTID_CONFIRM do
            not match, the server returns NFS4ERR_CLID_INUSE without
            removing any relevant leased client state, and without
            changing recorded callback and callback_ident values for
            client { x }.
          <vspace blankLines='1' />
            If the principals match, then what has likely
            happened is that the client never got the response
            from the SETCLIENTID_CONFIRM, and the DRC entry has been
            purged. Whatever the scenario, since the principals match,
            as well as { c, s } matching a confirmed record, the server
            leaves client x's relevant leased client state intact,
            leaves its callback and callback_ident values unmodified,
            and returns NFS4_OK.
          </t>

          <t>
            The server has not recorded a confirmed { *, *, c, *, * }
            and has recorded an unconfirmed { *, x, c, k, s }.
            Even if this is a retry from the client, nonetheless the
            client's first SETCLIENTID_CONFIRM attempt was not received
            by the server.  Retry or not, the server doesn't know, but
            it processes it as if it were a first try.  If the principal
            of the unconfirmed { *, x, c, k, s } record mismatches
            that of the SETCLIENTID_CONFIRM request, the server returns
            NFS4ERR_CLID_INUSE without removing any relevant leased
            client state.
          <vspace blankLines='1' />
            Otherwise, the server records a confirmed { *, x, c, k, s }.
            If there is also a confirmed { *, x, d, *, t }, the server
            MUST remove client x's relevant leased client state and
            overwrite the callback state with k. The confirmed
            record { *, x, d, *, t } is removed.
          <vspace blankLines='1' />
            The server returns NFS4_OK.
          </t>

          <t>
            The server has no record of a confirmed or unconfirmed { *,
            *, c, *, s }.  The server returns NFS4ERR_STALE_CLIENTID.
            The server does not remove any relevant leased client state,
            nor does it modify any recorded callback and callback_ident
            information for any client.
          </t>
        </list>
      </t>

      <t>
        The server needs to cache unconfirmed { v, x, c, k, s } client
        records and await for some time their confirmation.  As should
        be clear from the discussions of record processing for SETCLIENTID
        and SETCLIENTID_CONFIRM, there are cases where the server
        does not deterministically remove unconfirmed client records.
        To avoid running out of resources, the server is not required
        to hold unconfirmed records indefinitely.  One strategy the
        server might use is to set a limit on how many unconfirmed
        client records it will maintain and then, when the limit
        would be exceeded, remove the oldest record. Another strategy
        might be to remove an unconfirmed record when some amount of
        time has elapsed. The choice of the amount of time is fairly
        arbitrary, but it is surely no higher than the server's lease
        time period. Consider that leases need to be renewed before
        the lease time expires via an operation from the client.
        If the client cannot issue a SETCLIENTID_CONFIRM after a
        SETCLIENTID before a period of time equal to a lease expiration
        time, then the client is unlikely to be able to maintain state on
        the server during steady-state operation.
      </t>

      <t>
        If the client does send a SETCLIENTID_CONFIRM for an
        unconfirmed record that the server has already deleted, the
        client will get NFS4ERR_STALE_CLIENTID back.  If so, the client
        should then start over, and send SETCLIENTID to re-establish
        an unconfirmed client record and get back an unconfirmed
        client ID and setclientid_confirm verifier.  The client should
        then send the SETCLIENTID_CONFIRM to confirm the client ID.
      </t>

      <t>
        SETCLIENTID_CONFIRM does not establish or renew a lease.
        However, if SETCLIENTID_CONFIRM removes relevant leased client
        state, and that state does not include existing delegations,
        the server MUST allow the client a period of time no less
        than the value of the lease_time attribute, to reclaim (via
        the CLAIM_DELEGATE_PREV claim type of the OPEN operation)
        its delegations before removing unreclaimed delegations.
      </t>

    </section>
  </section>
  <section anchor="OP_VERIFY" title="Operation 37: VERIFY - Verify Same Attributes">

    <section toc="exclude" anchor="OP_VERIFY_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh), fattr -> -
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_VERIFY_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct VERIFY4args {
        /* CURRENT_FH: object */
        fattr4          obj_attributes;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_VERIFY_RESULT" title="RESULT">

<figure>
 <artwork>
struct VERIFY4res {
        nfsstat4        status;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_VERIFY_DESCRIPTION" title="DESCRIPTION">

      <t>
        The VERIFY operation is used to verify that attributes have a
        value assumed by the client before proceeding with subsequent
        operations in the COMPOUND request.  If any of the attributes
        do not match, then the error NFS4ERR_NOT_SAME must be returned.
        The current filehandle retains its value after successful
        completion of the operation.
      </t>

    </section>
    <section toc="exclude" anchor="OP_VERIFY_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        One possible use of the VERIFY operation is the following
        COMPOUND sequence.  With this, the client is attempting to
        verify that the file being removed will match what the client
        expects to be removed.  This sequence can help prevent the
        unintended deletion of a file.
      </t>

      <figure>
        <artwork>
  PUTFH (directory filehandle)
  LOOKUP (filename)
  VERIFY (filehandle == fh)
  PUTFH (directory filehandle)
  REMOVE (filename)
        </artwork>
      </figure>

      <t>
        This sequence does not prevent a second client from removing
        and creating a new file in the middle of this sequence, but
        it does help avoid the unintended result.
      </t>

      <t>
        In the case that a RECOMMENDED attribute is specified in the
        VERIFY operation and the server does not support that attribute
        for the file system object, the error NFS4ERR_ATTRNOTSUPP is
        returned to the client.
      </t>

      <t>
        When the attribute rdattr_error or any write-only attribute
        (e.g., time_modify_set) is specified, the error NFS4ERR_INVAL
        is returned to the client.
      </t>

    </section>
  </section>
  <section anchor="OP_WRITE" title="Operation 38: WRITE - Write to File">

    <section toc="exclude" anchor="OP_WRITE_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  (cfh), stateid, offset, stable, data -> count, committed, writeverf
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_WRITE_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
enum stable_how4 {
        UNSTABLE4       = 0,
        DATA_SYNC4      = 1,
        FILE_SYNC4      = 2
};

struct WRITE4args {
        /* CURRENT_FH: file */
        stateid4        stateid;
        offset4         offset;
        stable_how4     stable;
        opaque          data&lt;>;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_WRITE_RESULT" title="RESULT">

<figure>
 <artwork>
struct WRITE4resok {
        count4          count;
        stable_how4     committed;
        verifier4       writeverf;
};

union WRITE4res switch (nfsstat4 status) {
 case NFS4_OK:
         WRITE4resok    resok4;
 default:
         void;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_WRITE_DESCRIPTION" title="DESCRIPTION">

      <t>
        The WRITE operation is used to write data to a regular file.
        The target file is specified by the current filehandle.
        The offset specifies the offset where the data should be
        written.  An offset of 0 (zero) specifies that the write should
        start at the beginning of the file.  The count, as encoded
        as part of the opaque data parameter, represents the number
        of bytes of data that are to be written.  If the count is 0
        (zero), the WRITE will succeed and return a count of 0 (zero)
        subject to permissions checking.  The server may choose to
        write fewer bytes than requested by the client.
      </t>

      <t>
        Part of the WRITE request is a specification of how the WRITE
        is to be performed.  The client specifies with the stable
        parameter the method of how the data is to be processed
        by the server.  If stable is FILE_SYNC4,
        the server must commit the data written plus all file system
        metadata to stable storage before returning results.  This
        corresponds to the NFSv2 protocol semantics.  Any other
        behavior constitutes a protocol violation.  If stable is
        DATA_SYNC4, then the server must commit all of the
        data to stable storage and enough of the metadata to retrieve
        the data before returning.  The server implementer is free to
        implement DATA_SYNC4 in the same fashion as FILE_SYNC4, but
        with a possible performance drop.  If stable is UNSTABLE4,
        the server is free to commit any part of the
        data and the metadata to stable storage, including all or none,
        before returning a reply to the client. There is no guarantee
        whether or when any uncommitted data will subsequently be
        committed to stable storage. The only guarantees made by the
        server are that it will not destroy any data without changing
        the value of verf and that it will not commit the data and
        metadata at a level less than that requested by the client.
      </t>

      <t>
        The stateid value for a WRITE request represents a value
        returned from a previous byte-range lock or share reservation
        request or the stateid associated with a delegation.
        The stateid is used by the server to verify that
        the associated share reservation and any byte-range locks are
        still valid and to update lease timeouts for the client.
      </t>

      <t>
        Upon successful completion, the following results are returned.
        The count result is the number of bytes of data written to
        the file. The server may write fewer bytes than requested. If
        so, the actual number of bytes written starting at location,
        offset, is returned.
      </t>

      <t>
        The server also returns an indication of the level of
        commitment of the data and metadata via committed. If the
        server committed all data and metadata to stable storage,
        committed should be set to FILE_SYNC4. If the level of
        commitment was at least as strong as DATA_SYNC4, then
        committed should be set to DATA_SYNC4.  Otherwise, committed
        must be returned as UNSTABLE4. If stable was FILE4_SYNC, then
        committed must also be FILE_SYNC4: anything else constitutes a
        protocol violation. If stable was DATA_SYNC4, then committed
        may be FILE_SYNC4 or DATA_SYNC4: anything else constitutes a
        protocol violation. If stable was UNSTABLE4, then committed
        may be either FILE_SYNC4, DATA_SYNC4, or UNSTABLE4.
      </t>

      <t>
        The final portion of the result is the write verifier.
        The write verifier is a cookie that the client can use to
        determine whether the server has changed instance (boot) state
        between a call to WRITE and a subsequent call to either WRITE
        or COMMIT.  This cookie must be consistent during a single
        instance of the NFSv4 protocol service and must be
        unique between instances of the NFSv4 protocol server,
        where uncommitted data may be lost.
      </t>

      <t>
        If a client writes data to the server with the stable argument
        set to UNSTABLE4 and the reply yields a committed response
        of DATA_SYNC4 or UNSTABLE4, the client will follow up at some time
        in the future with a COMMIT operation to synchronize
        outstanding asynchronous data and metadata with the server's
        stable storage, barring client error. It is possible that due
        to client crash or other error a subsequent COMMIT will
        not be received by the server.
      </t>

      <t>
      For a WRITE using the special anonymous stateid, the server
      MAY allow the WRITE to be serviced subject to mandatory file
      locks or the current share deny modes for the file.  For a
      WRITE using the special READ bypass stateid, the server MUST NOT
      allow the WRITE operation to bypass locking checks at the
      server, and the WRITE is treated exactly the same as if the
      anonymous stateid were used.
      </t>

      <t>
        On success, the current filehandle retains its value.
      </t>

    </section>
    <section toc="exclude" anchor="OP_WRITE_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        It is possible for the server to write fewer bytes of data than
        requested by the client.  In this case, the server should not
        return an error unless no data was written at all.  If the
        server writes less than the number of bytes specified, the
        client should issue another WRITE to write the remaining data.
      </t>

      <t>
        It is assumed that the act of writing data to a file will
        cause the time_modify attribute of the file to be updated.
        However, the time_modify attribute of the file should not be
        changed unless the contents of the file are changed.  Thus, a
        WRITE request with count set to 0 should not cause the
        time_modify attribute of the file to be updated.
      </t>

      <t>
        The definition of stable storage has been historically a
        point of contention.  The following expected properties of
        stable storage may help in resolving design issues in the
        implementation. Stable storage is persistent storage that
        survives:

        <list style='numbers'>
          <t>
            Repeated power failures.
          </t>

          <t>
            Hardware failures (of any board, power supply, etc.).
          </t>

          <t>
            Repeated software crashes, including reboot cycle.
          </t>
        </list>
      </t>

      <t>
        This definition does not address failure of the stable storage
        module itself.
      </t>

      <t>
        The verifier is defined to allow a client to detect different
        instances of an NFSv4 protocol server over which
        cached, uncommitted data may be lost. In the most likely case,
        the verifier allows the client to detect server reboots.  This
        information is required so that the client can safely determine
        whether the server could have lost cached data.  If the server
        fails unexpectedly and the client has uncommitted data from
        previous WRITE requests (done with the stable argument set
        to UNSTABLE4 and in which the result committed was returned
        as UNSTABLE4 as well), it may not have flushed cached data to
        stable storage. The burden of recovery is on the client, and
        the client will need to retransmit the data to the server.
      </t>

      <t>
      One suggested way to use the verifier would be to use the time that
      the server was booted or the time the server was last started (if
      restarting the server without a reboot results in lost buffers).
      </t>

      <t>
        The committed field in the results allows the client to do
        more effective caching.  If the server is committing all
        WRITE requests to stable storage, then it should return with
        committed set to FILE_SYNC4, regardless of the value of the
        stable field in the arguments. A server that uses an NVRAM
        accelerator may choose to implement this policy.  The client
        can use this to increase the effectiveness of the cache by
        discarding cached data that has already been committed on
        the server.
      </t>

      <t>
        Some implementations may return NFS4ERR_NOSPC instead of
        NFS4ERR_DQUOT when a user's quota is exceeded.  In the case
        that the current filehandle is a directory, the server
        will return NFS4ERR_ISDIR.  If the current filehandle is
        not a regular file or a directory, the server will return
        NFS4ERR_INVAL.
      </t>

      <t>
        If mandatory file locking is on for the file, and a corresponding
        record of the data to be written to file is read or write locked
        by an owner that is not associated with the stateid, the server
        will return NFS4ERR_LOCKED. If so, the client must check if
        the owner corresponding to the stateid used with the WRITE
        operation has a conflicting read lock that overlaps with
        the region that was to be written. If the stateid's owner
        has no conflicting read lock, then the client should try to
        get the appropriate write byte-range lock via the LOCK operation
        before re-attempting the WRITE. When the WRITE completes,
        the client should release the byte-range lock via LOCKU.
      </t>

      <t>
        If the stateid's owner had a conflicting read lock, then
        the client has no choice but to return an error to the
        application that attempted the WRITE. The reason is that
        since the stateid's owner had a read lock, the server either
        (1) attempted to temporarily effectively upgrade this
        read lock to a write lock or (2) has no upgrade
        capability. If the server attempted to upgrade the read lock and
        failed, it is pointless for the client to re-attempt the upgrade via
        the LOCK operation, because there might be another client
        also trying to upgrade.  If two clients are blocked trying to
        upgrade the same lock, the clients deadlock.  If the server
        has no upgrade capability, then it is pointless to try a LOCK
        operation to upgrade.
      </t>

    </section>
  </section>
  <section anchor="OP_RELEASE_LOCKOWNER" title="Operation 39: RELEASE_LOCKOWNER - Release Lock-Owner State">

    <section toc="exclude" anchor="OP_RELEASE_LOCKOWNER_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  lock-owner -> ()
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_RELEASE_LOCKOWNER_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct RELEASE_LOCKOWNER4args {
        lock_owner4     lock_owner;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_RELEASE_LOCKOWNER_RESULT" title="RESULT">

<figure>
 <artwork>
struct RELEASE_LOCKOWNER4res {
        nfsstat4        status;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_RELEASE_LOCKOWNER_DESCRIPTION" title="DESCRIPTION">

      <t>
        This operation is used to notify the server that the lock_owner
        is no longer in use by the client and that future client requests
        will not reference this lock_owner. This allows the server
        to release cached state related to the specified lock_owner.
        If file locks associated with the lock_owner are held at
        the server, the error NFS4ERR_LOCKS_HELD will be returned
        and no further action will be taken.
      </t>

    </section>
    <section toc="exclude" anchor="OP_RELEASE_LOCKOWNER_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        The client may choose to use this operation to ease the
        amount of server state that is held.  Information that
        can be released when a RELEASE_LOCKOWNER is done includes
        the specified lock-owner string, the seqid associated with the 
        lock-owner, any saved reply for the lock-owner, and any
        lock stateids associated with that lock-owner.  
      </t>
      <t>
        Depending on the behavior of applications at the client, it
        may be important for the client to use this operation
        since the server has certain obligations with respect to
        holding a reference to lock-owner-associated state as long
        as an associated file is open.  Therefore, if the client
        knows for certain that the lock_owner will no longer be used
        to either reference existing lock stateids associated with the 
        lock-owner or create new ones, it should use RELEASE_LOCKOWNER.
      </t>

    </section>
  </section>
  <section anchor="OP_ILLEGAL" title="Operation 10044: ILLEGAL - Illegal Operation">

    <section toc="exclude" anchor="OP_ILLEGAL_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  &lt;null&gt; -> ()
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_ILLEGAL_ARGUMENT" title="ARGUMENT">

      <figure>
        <artwork>
  void;
        </artwork>
      </figure>

    </section>
    <section toc="exclude" anchor="OP_ILLEGAL_RESULT" title="RESULT">

<figure>
 <artwork>
struct ILLEGAL4res {
        nfsstat4        status;
};
 </artwork>
</figure>

    </section>
    <section toc="exclude" anchor="OP_ILLEGAL_DESCRIPTION" title="DESCRIPTION">

      <t>
        This operation is a placeholder for encoding a result to
        handle the case of the client sending an operation code within
        COMPOUND that is not supported. See
        <xref target="OP_COMPOUND_DESCRIPTION" /> for more details.
      </t>

      <t>
        The status field of ILLEGAL4res MUST be set to
        NFS4ERR_OP_ILLEGAL.
      </t>

    </section>
    <section toc="exclude" anchor="OP_ILLEGAL_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        A client will probably not send an operation with code
        OP_ILLEGAL, but if it does, the response will be ILLEGAL4res,
        just as it would be with any other invalid operation code. Note
        that if the server gets an illegal operation code that is
        not OP_ILLEGAL, and if the server checks for legal operation
        codes during the XDR decode phase, then the ILLEGAL4res would
        not be returned.
      </t>

    </section>
  </section>
 </section>

<section anchor="sec:callbackprocs" title="NFSv4 Callback Procedures">

  <t>
    The procedures used for callbacks are defined in the following
    sections.  In the interest of clarity, the terms "client" and
    "server" refer to NFS clients and servers, despite the fact that
    for an individual callback RPC, the sense of these terms would
    be precisely the opposite.
  </t>

  <t>

  </t>

  <section anchor="OP_CB_NULL" title="Procedure 0: CB_NULL - No Operation">

    <section toc="exclude" anchor="OP_CB_NULL_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  &lt;null&gt;
        </artwork>
      </figure>

    </section>

    <section toc="exclude" anchor="OP_CB_NULL_ARGUMENT" title="ARGUMENT">

      <figure>
        <artwork>
  void;
        </artwork>
      </figure>

    </section>

    <section toc="exclude" anchor="OP_CB_NULL_RESULT" title="RESULT">

      <figure>
        <artwork>
  void;
        </artwork>
      </figure>

    </section>

    <section toc="exclude" anchor="OP_CB_NULL_DESCRIPTION" title="DESCRIPTION">

      <t>
        Standard NULL procedure.  Void argument, void response.
        Even though there is no direct functionality associated with
        this procedure, the server will use CB_NULL to confirm the
        existence of a path for RPCs from server to client.
      </t>

    </section>
  </section>

  <section anchor="OP_CB_COMPOUND" title="Procedure 1: CB_COMPOUND - COMPOUND Operations">

    <section toc="exclude" anchor="OP_CB_COMPOUND_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  compoundargs -> compoundres
        </artwork>
      </figure>

    </section>

    <section toc="exclude" anchor="OP_CB_COMPOUND_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
enum nfs_cb_opnum4 {
        OP_CB_GETATTR           = 3,
        OP_CB_RECALL            = 4,
        OP_CB_ILLEGAL           = 10044
};
 </artwork>
</figure>
<figure>
 <artwork>
union nfs_cb_argop4 switch (unsigned argop) {
 case OP_CB_GETATTR:
      CB_GETATTR4args           opcbgetattr;
 case OP_CB_RECALL:
      CB_RECALL4args            opcbrecall;
 case OP_CB_ILLEGAL:            void;
};
 </artwork>
</figure>
<figure>
 <artwork>
struct CB_COMPOUND4args {
        utf8str_cs      tag;
        uint32_t        minorversion;
        uint32_t        callback_ident;
        nfs_cb_argop4   argarray&lt;>;
};
 </artwork>
</figure>

    </section>

    <section toc="exclude" anchor="OP_CB_COMPOUND_RESULT" title="RESULT">

<figure>
 <artwork>
union nfs_cb_resop4 switch (unsigned resop) {
 case OP_CB_GETATTR:    CB_GETATTR4res  opcbgetattr;
 case OP_CB_RECALL:     CB_RECALL4res   opcbrecall;
 case OP_CB_ILLEGAL:    CB_ILLEGAL4res  opcbillegal;
};
 </artwork>
</figure>
<figure>
 <artwork>
struct CB_COMPOUND4res {
        nfsstat4        status;
        utf8str_cs      tag;
        nfs_cb_resop4   resarray&lt;>;
};
 </artwork>
</figure>

    </section>

    <section toc="exclude" anchor="OP_CB_COMPOUND_DESCRIPTION" title="DESCRIPTION">

      <t>
        The CB_COMPOUND procedure is used to combine one or more of
        the callback procedures into a single RPC request.  The main
        callback RPC program has two main procedures: CB_NULL
        and CB_COMPOUND.  All other operations use the CB_COMPOUND
        procedure as a wrapper.
      </t>

      <t>
        In the processing of the CB_COMPOUND procedure, the client may
        find that it does not have the available resources to execute
        any or all of the operations within the CB_COMPOUND sequence.
        In this case, the error NFS4ERR_RESOURCE will be returned for
        the particular operation within the CB_COMPOUND procedure
        where the resource exhaustion occurred.  This assumes that
        all previous operations within the CB_COMPOUND sequence have
        been evaluated successfully.
      </t>

      <t>
        Contained within the CB_COMPOUND results is a status field.
        This status must be equivalent to the status of the last
        operation that was executed within the CB_COMPOUND procedure.
        Therefore, if an operation incurred an error, then the status
        value will be the same error value as is being returned for
        the operation that failed.
      </t>

      <t>
        For the definition of the tag field, see <xref target="OP_COMPOUND" />.
      </t>

      <t>
        The value of callback_ident is supplied by the client
        during SETCLIENTID.  The server must use the client-supplied
        callback_ident during the CB_COMPOUND to allow the client to
        properly identify the server.
      </t>

      <t>
        Illegal operation codes are handled in the same way as they
        are handled for the COMPOUND procedure.
      </t>

    </section>

    <section toc="exclude" anchor="OP_CB_COMPOUND_IMPLEMENTATION" title="IMPLEMENTATION">

      <t>
        The CB_COMPOUND procedure is used to combine individual
        operations into a single RPC request.  The client interprets
        each of the operations in turn.  If an operation is executed by
        the client and the status of that operation is NFS4_OK, then
        the next operation in the CB_COMPOUND procedure is executed.
        The client continues this process until there are no more
        operations to be executed or one of the operations has a
        status value other than NFS4_OK.
      </t>

    </section>
   </section>
  </section>

<section anchor="sec:callbackoperations" title="NFSv4 Callback Operations">

    <section anchor="OP_CB_GETATTR" title="Operation 3: CB_GETATTR - Get Attributes">

      <section toc="exclude" anchor="OP_CB_GETATTR_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  fh, attr_request -> attrmask, attr_vals
        </artwork>
      </figure>

      </section>
      <section toc="exclude" anchor="OP_CB_GETATTR_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct CB_GETATTR4args {
        nfs_fh4 fh;
        bitmap4 attr_request;
};
 </artwork>
</figure>

      </section>
      <section toc="exclude" anchor="OP_CB_GETATTR_RESULT" title="RESULT">

<figure>
 <artwork>
struct CB_GETATTR4resok {
        fattr4  obj_attributes;
};

union CB_GETATTR4res switch (nfsstat4 status) {
 case NFS4_OK:
         CB_GETATTR4resok       resok4;
 default:
         void;
};
 </artwork>
</figure>

      </section>
      <section toc="exclude" anchor="OP_CB_GETATTR_DESCRIPTION" title="DESCRIPTION">

        <t>
          The CB_GETATTR operation is used by the server to obtain the
          current modified state of a file that has been
          OPEN_DELEGATE_WRITE delegated. The size attribute and
          the change attribute are the only ones guaranteed
          to be serviced by the client.  See <xref target="ss:cc:handle_cb_getattr" />
          for a full description of how the client and
          server are to interact with the use of CB_GETATTR.
        </t>

        <t>
          If the filehandle specified is not one for which the client
          holds an OPEN_DELEGATE_WRITE delegation, an NFS4ERR_BADHANDLE error
          is returned.
        </t>

      </section>
      <section toc="exclude" anchor="OP_CB_GETATTR_IMPLEMENTATION" title="IMPLEMENTATION">

        <t>
          The client returns attrmask bits and the associated attribute
          values only for the change attribute, and attributes that it
          may change (time_modify and size).
        </t>

      </section>
    </section>
    <section anchor="OP_CB_RECALL" title="Operation 4: CB_RECALL - Recall an Open Delegation">

      <section toc="exclude" anchor="OP_CB_RECALL_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  stateid, truncate, fh -> ()
        </artwork>
      </figure>

      </section>
      <section toc="exclude" anchor="OP_CB_RECALL_ARGUMENT" title="ARGUMENT">

<figure>
 <artwork>
struct CB_RECALL4args {
        stateid4        stateid;
        bool            truncate;
        nfs_fh4         fh;
};
 </artwork>
</figure>

      </section>
      <section toc="exclude" anchor="OP_CB_RECALL_RESULT" title="RESULT">

<figure>
 <artwork>
struct CB_RECALL4res {
        nfsstat4        status;
};
 </artwork>
</figure>

      </section>
      <section toc="exclude" anchor="OP_CB_RECALL_DESCRIPTION" title="DESCRIPTION">

        <t>
          The CB_RECALL operation is used to begin the process of
          recalling an open delegation and returning it to the server.
        </t>

        <t>
          The truncate flag is used to optimize a recall for a file
          that is about to be truncated to zero.  When it is set,
          the client is freed of obligation to propagate modified data
          for the file to the server, since this data is irrelevant.
        </t>

        <t>
          If the handle specified is not one for which the client holds
          an open delegation, an NFS4ERR_BADHANDLE error is returned.
        </t>
  
        <t>
          If the stateid specified is not one corresponding to an
          open delegation for the file specified by the filehandle,
          an NFS4ERR_BAD_STATEID is returned.
        </t>

      </section>
      <section toc="exclude" anchor="OP_CB_RECALL_IMPLEMENTATION" title="IMPLEMENTATION">

        <t>
          The client should reply to the callback immediately.  Replying
          does not complete the recall, except when an error was returned.
          The recall is not complete until the delegation is returned
          using a DELEGRETURN.
        </t>

      </section>
    </section>
    <section anchor="OP_CB_ILLEGAL" title="Operation 10044: CB_ILLEGAL - Illegal Callback Operation">

      <section toc="exclude" anchor="OP_CB_ILLEGAL_SYNOPSIS" title="SYNOPSIS">

      <figure>
        <artwork>
  &lt;null&gt; -> ()
        </artwork>
      </figure>

      </section>
      <section toc="exclude" anchor="OP_CB_ILLEGAL_ARGUMENT" title="ARGUMENT">

      <figure>
        <artwork>
  void;
        </artwork>
      </figure>

      </section>
      <section toc="exclude" anchor="OP_CB_ILLEGAL_RESULT" title="RESULT">

<figure>
 <artwork>
/*
 * CB_ILLEGAL: Response for illegal operation numbers
 */
struct CB_ILLEGAL4res {
        nfsstat4        status;
};
 </artwork>
</figure>

      </section>
      <section toc="exclude" anchor="OP_CB_ILLEGAL_DESCRIPTION" title="DESCRIPTION">

        <t>
          This operation is a placeholder for encoding a result to
          handle the case of the client sending an operation code within
          COMPOUND that is not supported. See <xref target="OP_COMPOUND_DESCRIPTION" /> for more details.
        </t>

        <t>
          The status field of CB_ILLEGAL4res MUST be set to
          NFS4ERR_OP_ILLEGAL.
        </t>

      </section>
      <section toc="exclude" anchor="OP_CB_ILLEGAL_IMPLEMENTATION" title="IMPLEMENTATION">

        <t>
          A server will probably not send an operation with
          code OP_CB_ILLEGAL, but if it does, the response will be
          CB_ILLEGAL4res, just as it would be with any other invalid
          operation code. Note that if the client gets an illegal
          operation code that is not OP_ILLEGAL, and if the client
          checks for legal operation codes during the XDR decode phase,
          then the CB_ILLEGAL4res would not be returned.
        </t>

      </section>
    </section>
  </section>

<section anchor="sec:security" title="Security Considerations">
  <t>
    NFS has historically used a model where, from an authentication
    perspective, the client was the entire machine, or at least the
    source IP address of the machine.  The NFS server relied on the NFS
    client to make the proper authentication of the end-user.  The NFS
    server in turn shared its files only to specific clients, as
    identified by the client's source IP address.  Given this model, the
    AUTH_SYS RPC security flavor simply identified the end-user using the
    client to the NFS server.  When processing NFS responses, the client
    ensured that the responses came from the same IP address and port
    number that the request was sent to.  While such a model is easy to
    implement and simple to deploy and use, it is certainly not a safe
    model.  Thus, NFSv4 mandates that implementations support a security
    model that uses end-to-end authentication, where an end-user on a
    client mutually authenticates (via cryptographic schemes that do not
    expose passwords or keys in the clear on the network) to a
    principal on an NFS server.  Consideration should also be given
    to the integrity and privacy of NFS requests and responses.
    The issues of end-to-end mutual authentication, integrity,
    and privacy are discussed as part of <xref target="sec:rpc_flavors" />.
  </t>

  <t>
    When an NFSv4 mandated security model is used and a security principal or
    an NFSv4 name in user@dns_domain form needs to be translated to or from a
    local representation as described in
    <xref target='sec:fattr:owner_group' />, the translation SHOULD be
    done in a secure manner that preserves the integrity of the translation.
    For communication with a name service such as the
    Lightweight Directory Access Protocol (LDAP) (<xref target='RFC4511' />),
    this means employing a security service that uses authentication
    and data integrity. Kerberos and Transport Layer Security (TLS)
    (<xref target='RFC5246' />) are examples of such a security service.
  </t>

  <t>
    Note that being REQUIRED to implement does not mean REQUIRED to use;
    AUTH_SYS can be used by NFSv4 clients and servers.  However,
    AUTH_SYS is merely an OPTIONAL security flavor in NFSv4, and so
    interoperability via AUTH_SYS is not assured.
  </t>

  <t>
    For reasons of reduced administration overhead, better performance,
    and/or reduction of CPU utilization, users of NFSv4
    implementations may choose to not use security mechanisms that enable
    integrity protection on each remote procedure call and response. The
    use of mechanisms without integrity leaves the customer vulnerable to
    an attacker in between the NFS client and server that modifies the
    RPC request and/or the response. While implementations are free
    to provide the option to use weaker security mechanisms, there
    are two operations in particular that warrant the implementation
    overriding user choices.
  </t>

  <t>
    The first such operation is SECINFO.  It is recommended that the
    client issue the SECINFO call such that it is protected with a
    security flavor that has integrity protection, such as RPCSEC_GSS
    with a security triple that uses either rpc_gss_svc_integrity or
    rpc_gss_svc_privacy (rpc_gss_svc_privacy includes integrity
    protection) service. Without integrity protection encapsulating
    SECINFO and therefore its results, an attacker in the middle could
    modify results such that the client might select a weaker algorithm
    in the set allowed by the server, making the client and/or server
    vulnerable to further attacks.
  </t>

  <t>
    The second operation that SHOULD use integrity protection
    is any GETATTR for the fs_locations attribute. The attack has two
    steps.  First, the attacker modifies the unprotected results of
    some operation to return NFS4ERR_MOVED. Second, when the client
    follows up with a GETATTR for the fs_locations attribute, the
    attacker modifies the results to cause the client to migrate its
    traffic to a server controlled by the attacker.
  </t>

  <t>
    Because the operations SETCLIENTID/SETCLIENTID_CONFIRM are
    responsible for the release of client state, it is imperative
    that the principal used for these operations is checked against
    and matches with the previous use of these operations. See
     <xref target="ss:fl:client_id" /> for further discussion.
  </t>

  <t>
    Unicode in the form of UTF-8 is used for file
    component names (i.e., both directory and file components),
    as well as the owner and owner_group
    attributes; other character sets may also be allowed for
    file component names.  String processing
    (e.g., Unicode normalization) raises security concerns for
    string comparison.  See Sections
    <xref target="sec:fattr:owner_group" format="counter" /> and
    <xref target="sec:i18n" format="counter" /> for further
    discussion, and see <xref target='RFC6943' /> for related
    identifier comparison security considerations.  File component
    names are identifiers with respect to the identifier comparison
    discussion in <xref target='RFC6943' /> because they are used to
    identify the objects to which ACLs are applied;
    see <xref target='sec:acl' />.
  </t>
</section>

<section anchor="sec:iana" title="IANA Considerations">
  <t>
    This section uses terms that are defined in <xref target="RFC5226"/>.
  </t>

 <section anchor="namedattributesiana" title="Named Attribute Definitions">
   <t>
     IANA has created a registry called the "NFSv4 Named Attribute Definitions Registry"
     for <xref target="RFC3530" /> and <xref target="RFC5661" />. This section introduces no new
     changes, but it does recap the intent.

   </t>
   <t>
     The NFSv4 protocol supports the association of a file with zero or
     more named attributes.  The namespace identifiers for these attributes
     are defined as string names.  The protocol does not define the
     specific assignment of the namespace for these file attributes.
     The IANA registry promotes interoperability
     where common interests exist.  While application developers are
     allowed to define and use attributes as needed, they are encouraged
     to register the attributes with IANA.
   </t>
   <t>
     Such registered named attributes are presumed to apply to all minor
     versions of NFSv4, including those defined subsequently to the registration.
     Where the named attribute is intended to be limited with regard to
     the minor versions for which they are not to be used, the
     assignment in the registry will clearly state the applicable
     limits.
   </t>
   <t>
     The registry is to be maintained using the Specification Required
     policy as defined in Section 4.1 of <xref target="RFC5226"/>.
   </t>
   <t>
     Under the NFSv4 specification, the name of a named
     attribute can in theory be up to 2^32 - 1 bytes in
     length, but in practice NFSv4 clients and servers
     will be unable to handle a string that long. IANA
     should reject any assignment request with a named
     attribute that exceeds 128 UTF-8 characters. To give
     the IESG the flexibility to set up bases of assignment
     of Experimental Use and Standards Action,
     the prefixes of "EXPE" and "STDS" are Reserved.
     The zero-length named attribute name is Reserved.
   </t>
   <t>
     The prefix "PRIV" is allocated for Private Use.  A
     site that wants to make use of unregistered named
     attributes without risk of conflicting with an
     assignment in IANA's registry should use the prefix
     "PRIV" in all of its named attributes.
   </t>
   <t>
     Because some NFSv4 clients and servers have case-insensitive
     semantics, the fifteen additional lowercase and mixed-case
     permutations of each of "EXPE", "PRIV", and "STDS" are
     Reserved (e.g., "expe", "expE", "exPe", etc. are Reserved).
     Similarly, IANA must not allow two assignments that would conflict
     if both named attributes were converted to a common case.
   </t>

   <t>
     The registry of named attributes is a list of assignments, each
     containing three fields for each assignment.

     <list style='numbers'>
       <t>
         A US-ASCII string name that is the actual name of
         the attribute. This name must be unique.  This
         string name can be 1 to 128 UTF-8 characters
         long.
       </t>

       <t>
         A reference to the specification of the named attribute.
          The reference can consume up to 256 bytes (or more, if IANA
          permits).
       </t>

       <t>
         The point of contact of the registrant. The point of contact
         can consume up to 256 bytes (or more, if IANA permits).
       </t>
     </list>
   </t>

  <section title="Initial Registry">
  <t>
   There is no initial registry.
  </t>
  </section>

  <section title="Updating Registrations">
  <t>
    The registrant is always permitted to update the point of contact
    field. To make any other change will require Expert Review or IESG
    Approval.
  </t>
  </section>

 </section>

<section title="Updates to Existing IANA Registries">
   <t>
   In addition, because this document obsoletes RFC 3530, IANA has

    <list style="symbols">
     <t>
     replaced all references to RFC 3530 in the Network Identifier (r_netid)
     registry with references to this document.
     </t>

     <t>
     replaced the reference to the nfs registration's reference to
     RFC&nbsp;3530 in the GSSAPI/Kerberos/SASL Service names registry
     with a reference to this document.
     </t>
    </list>

   </t>
 </section>
</section>

</middle>

<back>

<references title="Normative References">
  <?rfc sortrefs="yes"?>

    <reference  anchor='RFC20' target='http://www.rfc-editor.org/info/rfc20'>
    <front>
    <title>ASCII format for network interchange</title>
    <author initials='V.G.' surname='Cerf' fullname='V.G. Cerf'><organization /></author>
    <date year='1969' month='October' />
    </front>
    <seriesInfo name='STD' value='80'/>
    <seriesInfo name='RFC' value='20'/>
    <format type='ASCII' octets='18504'/>
    </reference>

  <reference anchor="UNICODE" target="http://www.unicode.org/versions/latest/">
    <front>
      <title>The Unicode Standard, Version 7.0.0</title>
      <author>
        <organization>The Unicode Consortium</organization>
      </author>
      <date year="2014" month="June"/>
    </front>
    <seriesInfo name="(Mountain View, CA: The Unicode Consortium, 2014"
                value="ISBN 978-1-936213-09-2)"/>
  </reference>

    <reference  anchor='RFC2119' target='http://www.rfc-editor.org/info/rfc2119'>
    <front>
    <title>Key words for use in RFCs to Indicate Requirement Levels</title>
    <author initials='S.' surname='Bradner' fullname='S. Bradner'><organization /></author>
    <date year='1997' month='March' />
    </front>
    <seriesInfo name='BCP' value='14'/>
    <seriesInfo name='RFC' value='2119'/>
    <format type='ASCII' octets='4723'/>
    </reference>

    <reference  anchor='RFC2203' target='http://www.rfc-editor.org/info/rfc2203'>
    <front>
    <title>RPCSEC_GSS Protocol Specification</title>
    <author initials='M.' surname='Eisler' fullname='M. Eisler'><organization /></author>
    <author initials='A.' surname='Chiu' fullname='A. Chiu'><organization /></author>
    <author initials='L.' surname='Ling' fullname='L. Ling'><organization /></author>
    <date year='1997' month='September' />
    </front>
    <seriesInfo name='RFC' value='2203'/>
    <format type='ASCII' octets='50937'/>
    </reference>

    <reference  anchor='RFC2743' target='http://www.rfc-editor.org/info/rfc2743'>
    <front>
    <title>Generic Security Service Application Program Interface Version 2, Update 1</title>
    <author initials='J.' surname='Linn' fullname='J. Linn'><organization /></author>
    <date year='2000' month='January' />
    </front>
    <seriesInfo name='RFC' value='2743'/>
    <format type='ASCII' octets='229418'/>
    </reference>

    <reference  anchor='RFC3490' target='http://www.rfc-editor.org/info/rfc3490'>
    <front>
    <title>Internationalizing Domain Names in Applications (IDNA)</title>
    <author initials='P.' surname='Faltstrom' fullname='P. Faltstrom'><organization /></author>
    <author initials='P.' surname='Hoffman' fullname='P. Hoffman'><organization /></author>
    <author initials='A.' surname='Costello' fullname='A. Costello'><organization /></author>
    <date year='2003' month='March' />
    </front>
    <seriesInfo name='RFC' value='3490'/>
    <format type='ASCII' octets='51943'/>
    </reference>

    <reference  anchor='RFC3492' target='http://www.rfc-editor.org/info/rfc3492'>
    <front>
    <title>Punycode: A Bootstring encoding of Unicode for Internationalized Domain Names in Applications (IDNA)</title>
    <author initials='A.' surname='Costello' fullname='A. Costello'><organization /></author>
    <date year='2003' month='March' />
    </front>
    <seriesInfo name='RFC' value='3492'/>
    <format type='ASCII' octets='67439'/>
    </reference>

    <reference  anchor='RFC3629' target='http://www.rfc-editor.org/info/rfc3629'>
    <front>
    <title>UTF-8, a transformation format of ISO 10646</title>
    <author initials='F.' surname='Yergeau' fullname='F. Yergeau'><organization /></author>
    <date year='2003' month='November' />
    </front>
    <seriesInfo name='STD' value='63'/>
    <seriesInfo name='RFC' value='3629'/>
    <format type='ASCII' octets='33856'/>
    </reference>

    <reference  anchor='RFC5226' target='http://www.rfc-editor.org/info/rfc5226'>
    <front>
    <title>Guidelines for Writing an IANA Considerations Section in RFCs</title>
    <author initials='T.' surname='Narten' fullname='T. Narten'><organization /></author>
    <author initials='H.' surname='Alvestrand' fullname='H. Alvestrand'><organization /></author>
    <date year='2008' month='May' />
    </front>
    <seriesInfo name='BCP' value='26'/>
    <seriesInfo name='RFC' value='5226'/>
    <format type='ASCII' octets='66160'/>
    </reference>

    <reference  anchor='RFC5403' target='http://www.rfc-editor.org/info/rfc5403'>
    <front>
    <title>RPCSEC_GSS Version 2</title>
    <author initials='M.' surname='Eisler' fullname='M. Eisler'><organization /></author>
    <date year='2009' month='February' />
    </front>
    <seriesInfo name='RFC' value='5403'/>
    <format type='ASCII' octets='30812'/>
    </reference>

    <reference  anchor='RFC5531' target='http://www.rfc-editor.org/info/rfc5531'>
    <front>
    <title>RPC: Remote Procedure Call Protocol Specification Version 2</title>
    <author initials='R.' surname='Thurlow' fullname='R. Thurlow'><organization /></author>
    <date year='2009' month='May' />
    </front>
    <seriesInfo name='RFC' value='5531'/>
    <format type='ASCII' octets='161720'/>
    </reference>

    <reference  anchor='RFC5665' target='http://www.rfc-editor.org/info/rfc5665'>
    <front>
    <title>IANA Considerations for Remote Procedure Call (RPC) Network Identifiers and Universal Address Formats</title>
    <author initials='M.' surname='Eisler' fullname='M. Eisler'><organization /></author>
    <date year='2010' month='January' />
    </front>
    <seriesInfo name='RFC' value='5665'/>
    <format type='ASCII' octets='28706'/>
    </reference>

    <reference  anchor='RFC5890' target='http://www.rfc-editor.org/info/rfc5890'>
    <front>
    <title>Internationalized Domain Names for Applications (IDNA): Definitions and Document Framework</title>
    <author initials='J.' surname='Klensin' fullname='J. Klensin'><organization /></author>
    <date year='2010' month='August' />
    </front>
    <seriesInfo name='RFC' value='5890'/>
    <format type='ASCII' octets='54245'/>
    </reference>

    <reference  anchor='RFC5891' target='http://www.rfc-editor.org/info/rfc5891'>
    <front>
    <title>Internationalized Domain Names in Applications (IDNA): Protocol</title>
    <author initials='J.' surname='Klensin' fullname='J. Klensin'><organization /></author>
    <date year='2010' month='August' />
    </front>
    <seriesInfo name='RFC' value='5891'/>
    <format type='ASCII' octets='38105'/>
    </reference>

    <reference  anchor='RFC6649' target='http://www.rfc-editor.org/info/rfc6649'>
    <front>
    <title>Deprecate DES, RC4-HMAC-EXP, and Other Weak Cryptographic Algorithms in Kerberos</title>
    <author initials='L.' surname='Hornquist Astrand' fullname='L. Hornquist Astrand'><organization /></author>
    <author initials='T.' surname='Yu' fullname='T. Yu'><organization /></author>
    <date year='2012' month='July' />
    </front>
    <seriesInfo name='BCP' value='179'/>
    <seriesInfo name='RFC' value='6649'/>
    <format type='ASCII' octets='13498'/>
    </reference>

<!-- draft-ietf-nfsv4-rfc3530bis-dot-x (RFC 7531) -->
   <reference anchor='RFC7531' target='http://www.rfc-editor.org/info/rfc7531'>
      <front>
        <title>Network File System (NFS) Version 4 External Data Representation Standard (XDR) Description</title>
        <author initials='T' surname='Haynes' fullname='Thomas Haynes' role="editor">
          <organization />
        </author>
        <author initials='D' surname='Noveck' fullname='David Noveck' role="editor">
          <organization />
        </author>
        <date month='March' year='2015' />
      </front>
      <seriesInfo name='RFC' value='7531' />
    </reference>

    <reference anchor="openg_symlink" target="http://www.opengroup.org/">
      <front>
     <title>
      Section 3.372 of Chapter 3 of Base Definitions
      of The Open Group Base Specifications Issue 7
     </title>
  <author>
    <organization>The Open Group</organization>
  </author>
  <date month="April" year="2013" />
      </front>
     <seriesInfo name="IEEE Std 1003.1, 2013 Edition (HTML Version),"
       value="ISBN 1937218287"/>
    </reference>

  <reference anchor="SPECIALCASING" target="http://www.unicode.org/Public/UCD/latest/ucd/SpecialCasing.txt">
    <front>
      <title>SpecialCasing-7.0.0.txt</title>
      <author>
        <organization>The Unicode Consortium</organization>
      </author>
      <date year="2014" month="March"/>
    </front>
    <seriesInfo name='Unicode Character' value='Database' />
  </reference>

  </references>

  <references title="Informative References">

    <reference  anchor='RFC1094' target='http://www.rfc-editor.org/info/rfc1094'>
    <front>
    <title>NFS: Network File System Protocol specification</title>
    <author initials='B.' surname='Nowicki' fullname='B. Nowicki'><organization /></author>
    <date year='1989' month='March' />
    </front>
    <seriesInfo name='RFC' value='1094'/>
    <format type='ASCII' octets='51454'/>
    </reference>

    <reference  anchor='RFC1813' target='http://www.rfc-editor.org/info/rfc1813'>
    <front>
    <title>NFS Version 3 Protocol Specification</title>
    <author initials='B.' surname='Callaghan' fullname='B. Callaghan'><organization /></author>
    <author initials='B.' surname='Pawlowski' fullname='B. Pawlowski'><organization /></author>
    <author initials='P.' surname='Staubach' fullname='P. Staubach'><organization /></author>
    <date year='1995' month='June' />
    </front>
    <seriesInfo name='RFC' value='1813'/>
    <format type='ASCII' octets='229793'/>
    </reference>

    <reference  anchor='RFC1833' target='http://www.rfc-editor.org/info/rfc1833'>
    <front>
    <title>Binding Protocols for ONC RPC Version 2</title>
    <author initials='R.' surname='Srinivasan' fullname='R. Srinivasan'><organization /></author>
    <date year='1995' month='August' />
    </front>
    <seriesInfo name='RFC' value='1833'/>
    <format type='ASCII' octets='24449'/>
    </reference>

    <reference  anchor='RFC2054' target='http://www.rfc-editor.org/info/rfc2054'>
    <front>
    <title>WebNFS Client Specification</title>
    <author initials='B.' surname='Callaghan' fullname='B. Callaghan'><organization /></author>
    <date year='1996' month='October' />
    </front>
    <seriesInfo name='RFC' value='2054'/>
    <format type='ASCII' octets='36354'/>
    </reference>

    <reference  anchor='RFC2055' target='http://www.rfc-editor.org/info/rfc2055'>
    <front>
    <title>WebNFS Server Specification</title>
    <author initials='B.' surname='Callaghan' fullname='B. Callaghan'><organization /></author>
    <date year='1996' month='October' />
    </front>
    <seriesInfo name='RFC' value='2055'/>
    <format type='ASCII' octets='20498'/>
    </reference>

    <reference  anchor='RFC2224' target='http://www.rfc-editor.org/info/rfc2224'>
    <front>
    <title>NFS URL Scheme</title>
    <author initials='B.' surname='Callaghan' fullname='B. Callaghan'><organization /></author>
    <date year='1997' month='October' />
    </front>
    <seriesInfo name='RFC' value='2224'/>
    <format type='ASCII' octets='22726'/>
    </reference>

    <reference  anchor='RFC2623' target='http://www.rfc-editor.org/info/rfc2623'>
    <front>
    <title>NFS Version 2 and Version 3 Security Issues and the NFS Protocol's Use of RPCSEC_GSS and Kerberos V5</title>
    <author initials='M.' surname='Eisler' fullname='M. Eisler'><organization /></author>
    <date year='1999' month='June' />
    </front>
    <seriesInfo name='RFC' value='2623'/>
    <format type='ASCII' octets='42521'/>
    </reference>

    <reference  anchor='RFC2624' target='http://www.rfc-editor.org/info/rfc2624'>
    <front>
    <title>NFS Version 4 Design Considerations</title>
    <author initials='S.' surname='Shepler' fullname='S. Shepler'><organization /></author>
    <date year='1999' month='June' />
    </front>
    <seriesInfo name='RFC' value='2624'/>
    <format type='ASCII' octets='52891'/>
    </reference>

    <reference  anchor='RFC2755' target='http://www.rfc-editor.org/info/rfc2755'>
    <front>
    <title>Security Negotiation for WebNFS</title>
    <author initials='A.' surname='Chiu' fullname='A. Chiu'><organization /></author>
    <author initials='M.' surname='Eisler' fullname='M. Eisler'><organization /></author>
    <author initials='B.' surname='Callaghan' fullname='B. Callaghan'><organization /></author>
    <date year='2000' month='January' />
    </front>
    <seriesInfo name='RFC' value='2755'/>
    <format type='ASCII' octets='23493'/>
    </reference>

    <reference  anchor='RFC3010' target='http://www.rfc-editor.org/info/rfc3010'>
    <front>
    <title>NFS version 4 Protocol</title>
    <author initials='S.' surname='Shepler' fullname='S. Shepler'><organization /></author>
    <author initials='B.' surname='Callaghan' fullname='B. Callaghan'><organization /></author>
    <author initials='D.' surname='Robinson' fullname='D. Robinson'><organization /></author>
    <author initials='R.' surname='Thurlow' fullname='R. Thurlow'><organization /></author>
    <author initials='C.' surname='Beame' fullname='C. Beame'><organization /></author>
    <author initials='M.' surname='Eisler' fullname='M. Eisler'><organization /></author>
    <author initials='D.' surname='Noveck' fullname='D. Noveck'><organization /></author>
    <date year='2000' month='December' />
    </front>
    <seriesInfo name='RFC' value='3010'/>
    <format type='ASCII' octets='450434'/>
    </reference>

    <reference  anchor='RFC3232' target='http://www.rfc-editor.org/info/rfc3232'>
    <front>
    <title>Assigned Numbers: RFC 1700 is Replaced by an On-line Database</title>
    <author initials='J.' surname='Reynolds' fullname='J. Reynolds' role='editor'><organization /></author>
    <date year='2002' month='January' />
    </front>
    <seriesInfo name='RFC' value='3232'/>
    <format type='ASCII' octets='3849'/>
    </reference>

    <reference  anchor='RFC3530' target='http://www.rfc-editor.org/info/rfc3530'>
    <front>
    <title>Network File System (NFS) version 4 Protocol</title>
    <author initials='S.' surname='Shepler' fullname='S. Shepler'><organization /></author>
    <author initials='B.' surname='Callaghan' fullname='B. Callaghan'><organization /></author>
    <author initials='D.' surname='Robinson' fullname='D. Robinson'><organization /></author>
    <author initials='R.' surname='Thurlow' fullname='R. Thurlow'><organization /></author>
    <author initials='C.' surname='Beame' fullname='C. Beame'><organization /></author>
    <author initials='M.' surname='Eisler' fullname='M. Eisler'><organization /></author>
    <author initials='D.' surname='Noveck' fullname='D. Noveck'><organization /></author>
    <date year='2003' month='April' />
    </front>
    <seriesInfo name='RFC' value='3530'/>
    <format type='ASCII' octets='600988'/>
    </reference>

    <reference  anchor='RFC4121' target='http://www.rfc-editor.org/info/rfc4121'>
    <front>
    <title>The Kerberos Version 5 Generic Security Service Application Program Interface (GSS-API) Mechanism: Version 2</title>
    <author initials='L.' surname='Zhu' fullname='L. Zhu'><organization /></author>
    <author initials='K.' surname='Jaganathan' fullname='K. Jaganathan'><organization /></author>
    <author initials='S.' surname='Hartman' fullname='S. Hartman'><organization /></author>
    <date year='2005' month='July' />
    </front>
    <seriesInfo name='RFC' value='4121'/>
    <format type='ASCII' octets='340314'/>
    </reference>

    <reference  anchor='RFC4178' target='http://www.rfc-editor.org/info/rfc4178'>
    <front>
    <title>The Simple and Protected Generic Security Service Application Program Interface (GSS-API) Negotiation Mechanism</title>
    <author initials='L.' surname='Zhu' fullname='L. Zhu'><organization /></author>
    <author initials='P.' surname='Leach' fullname='P. Leach'><organization /></author>
    <author initials='K.' surname='Jaganathan' fullname='K. Jaganathan'><organization /></author>
    <author initials='W.' surname='Ingersoll' fullname='W. Ingersoll'><organization /></author>
    <date year='2005' month='October' />
    </front>
    <seriesInfo name='RFC' value='4178'/>
    <format type='ASCII' octets='46485'/>
    </reference>

    <reference  anchor='RFC4506' target='http://www.rfc-editor.org/info/rfc4506'>
    <front>
    <title>XDR: External Data Representation Standard</title>
    <author initials='M.' surname='Eisler' fullname='M. Eisler' role='editor'><organization /></author>
    <date year='2006' month='May' />
    </front>
    <seriesInfo name='STD' value='67'/>
    <seriesInfo name='RFC' value='4506'/>
    <format type='ASCII' octets='55477'/>
    </reference>

    <reference  anchor='RFC4511' target='http://www.rfc-editor.org/info/rfc4511'>
    <front>
    <title>Lightweight Directory Access Protocol (LDAP): The Protocol</title>
    <author initials='J.' surname='Sermersheim' fullname='J. Sermersheim' role='editor'><organization /></author>
    <date year='2006' month='June' />
    </front>
    <seriesInfo name='RFC' value='4511'/>
    <format type='ASCII' octets='150116'/>
    </reference>

    <reference  anchor='RFC5246' target='http://www.rfc-editor.org/info/rfc5246'>
    <front>
    <title>The Transport Layer Security (TLS) Protocol Version 1.2</title>
    <author initials='T.' surname='Dierks' fullname='T. Dierks'><organization /></author>
    <author initials='E.' surname='Rescorla' fullname='E. Rescorla'><organization /></author>
    <date year='2008' month='August' />
    </front>
    <seriesInfo name='RFC' value='5246'/>
    <format type='ASCII' octets='222395'/>
    </reference>

    <reference  anchor='RFC5661' target='http://www.rfc-editor.org/info/rfc5661'>
    <front>
    <title>Network File System (NFS) Version 4 Minor Version 1 Protocol</title>
    <author initials='S.' surname='Shepler' fullname='S. Shepler' role='editor'><organization /></author>
    <author initials='M.' surname='Eisler' fullname='M. Eisler' role='editor'><organization /></author>
    <author initials='D.' surname='Noveck' fullname='D. Noveck' role='editor'><organization /></author>
    <date year='2010' month='January' />
    </front>
    <seriesInfo name='RFC' value='5661'/>
    <format type='ASCII' octets='1517771'/>
    </reference>

    <reference  anchor='RFC6365' target='http://www.rfc-editor.org/info/rfc6365'>
    <front>
    <title>Terminology Used in Internationalization in the IETF</title>
    <author initials='P.' surname='Hoffman' fullname='P. Hoffman'><organization /></author>
    <author initials='J.' surname='Klensin' fullname='J. Klensin'><organization /></author>
    <date year='2011' month='September' />
    </front>
    <seriesInfo name='BCP' value='166'/>
    <seriesInfo name='RFC' value='6365'/>
    <format type='ASCII' octets='103155'/>
    </reference>

    <reference  anchor='RFC6943' target='http://www.rfc-editor.org/info/rfc6943'>
    <front>
    <title>Issues in Identifier Comparison for Security Purposes</title>
    <author initials='D.' surname='Thaler' fullname='D. Thaler' role='editor'><organization /></author>
    <date year='2013' month='May' />
    </front>
    <seriesInfo name='RFC' value='6943'/>
    <format type='ASCII' octets='62676'/>
    </reference>

    <reference anchor="Floyd">
        <front>
            <title> The Synchronization of Periodic Routing Messages </title>
            <author initials="S." surname="Floyd" >
            <organization></organization>
            </author>
            <author initials="V." surname="Jacobson">
            <organization></organization>
            </author>
            <date month="April" year="1994"/>
        </front>
        <seriesInfo name="IEEE/ACM Transactions on Networking" value="2(2), pp. 122-136" />
    </reference>

    <reference anchor="Chet">
        <front>
            <title>Improving the Performance
                    and Correctness of an NFS Server</title>
            <author initials="C." surname="Juszczak" fullname="Chet Juszczak">
              <organization>Digital Equipment Corporation</organization>
            </author>
            <date month="June" year="1990"/>
        </front>
        <seriesInfo name="USENIX" value="Conference Proceedings" />
      </reference>

    <reference anchor="xnfs">
        <front>
            <title> Protocols for Interworking: XNFS, Version 3W, ISBN 1-85912-184-5 </title>
            <author>
              <organization>The Open Group </organization>
            </author>
            <date month="February" year="1998"/>
        </front>
      </reference>

<reference anchor='IESG_ERRATA'>
<front>
<title>IESG Processing of RFC Errata for the IETF Stream</title>
        <author>
<organization>IESG</organization>
        </author>
<date year='2008' month='July' />
</front>
</reference>

    <reference anchor="read_api" target="http://www.opengroup.org/">
      <front>
     <title>Section 'read()' of System Interfaces of The Open Group Base Specifications Issue 7
     </title>
        <author>
          <organization>The Open Group</organization>
        </author>
        <date month="April" year="2013" />
      </front>
     <seriesInfo name="IEEE Std 1003.1, 2013 Edition (HTML Version),"
       value="ISBN 1937218287"/>
    </reference>

    <reference anchor="readdir_api" target="http://www.opengroup.org/">
      <front>
     <title>Section 'readdir()' of System Interfaces of The Open Group Base Specifications Issue 7
     </title>
        <author>
          <organization>The Open Group</organization>
        </author>
        <date month="April" year="2013" />
      </front>
     <seriesInfo name="IEEE Std 1003.1, 2013 Edition (HTML Version),"
       value="ISBN 1937218287"/>
    </reference>

    <reference anchor="stat" target="http://www.opengroup.org/">
      <front>
     <title>Section 'stat()' of System Interfaces of The Open Group Base Specifications Issue 7
     </title>
        <author>
          <organization>The Open Group</organization>
        </author>
        <date month="April" year="2013" />
      </front>
     <seriesInfo name="IEEE Std 1003.1, 2013 Edition (HTML Version),"
       value="ISBN 1937218287"/>
    </reference>

    <reference anchor="write_api" target="http://www.opengroup.org/">
      <front>
     <title>Section 'write()' of System Interfaces of The Open Group Base Specifications Issue 7
     </title>
        <author>
          <organization>The Open Group</organization>
        </author>
        <date month="April" year="2013" />
      </front>
     <seriesInfo name="IEEE Std 1003.1, 2013 Edition (HTML Version),"
       value="ISBN 1937218287"/>
    </reference>

    <reference anchor="fcntl" target="http://www.opengroup.org/">
      <front>
              <title>
          Section 'fcntl()' of System Interfaces of The
          Open Group Base Specifications Issue 7
        </title>
              <author>
                <organization>The Open Group</organization>
              </author>
              <date month="April" year="2013"/>
      </front>
     <seriesInfo name="IEEE Std 1003.1, 2013 Edition (HTML Version),"
       value="ISBN 1937218287"/>
    </reference>

    <reference anchor="fsync" target="http://www.opengroup.org/">
      <front>
              <title>
         Section 'fsync()' of System Interfaces of The
         Open Group Base Specifications Issue 7
        </title>
              <author>
                <organization>The Open Group</organization>
              </author>
              <date month="April" year="2013"/>
      </front>
     <seriesInfo name="IEEE Std 1003.1, 2013 Edition (HTML Version),"
       value="ISBN 1937218287"/>
    </reference>

    <reference anchor="getpwnam" target="http://www.opengroup.org/">
      <front>
              <title>
         Section 'getpwnam()' of System Interfaces of
         The Open Group Base Specifications Issue 7
        </title>
              <author>
                <organization>The Open Group</organization>
              </author>
              <date month="April" year="2013"/>
      </front>
     <seriesInfo name="IEEE Std 1003.1, 2013 Edition (HTML Version),"
       value="ISBN 1937218287"/>
    </reference>

    <reference anchor="unlink" target="http://www.opengroup.org/">
      <front>
              <title>
         Section 'unlink()' of System Interfaces of The
         Open Group Base Specifications Issue 7
        </title>
              <author>
                <organization>The Open Group</organization>
              </author>
              <date month="April" year="2013"/>
      </front>
     <seriesInfo name="IEEE Std 1003.1, 2013 Edition (HTML Version),"
       value="ISBN 1937218287"/>
    </reference>

  <reference anchor="P1003.1e">
      <front>
     <title>IEEE Draft P1003.1e
     </title>
  <author>
    <organization>Institute of Electrical and Electronics Engineers, Inc.
    </organization>
  </author>
  <date year="1997" />
      </front>
    </reference>

<reference anchor="MS-SMB">
        <front>
                <title>Server Message Block (SMB) Protocol Specification</title>
                <author fullname="Microsoft Corporation">
                        <organization>Microsoft Corporation</organization>
                </author>
                <date month="May" year="2014" />
        </front>
        <seriesInfo name="MS-SMB" value="43.0"/>
</reference>


</references>

<section title="Acknowledgments" numbered="no">
  <t>
   A bis is certainly built on the shoulders of the first attempt.
   Spencer Shepler, Brent Callaghan, David Robinson, Robert Thurlow,
   Carl Beame, Mike Eisler, and David Noveck are responsible for a
   great deal of the effort in this work.
  </t>
  <t>
    Tom Haynes would like to thank NetApp, Inc. for its funding of
    his time on this project.
  </t>
  <t>
    Rob Thurlow clarified how a client should contact a new server
    if a migration has occurred.
  </t>
  <t>
    David Black, Nico Williams, Mike Eisler, Trond Myklebust,
    James Lentini, and Mike Kupfer read many earlier draft versions
    of <xref target="sec:i18n" /> and contributed numerous useful
    suggestions, without which the necessary revision of that
    section for this document would not have been possible.
  </t>
  <t>
    Peter Staubach read almost all of the earlier draft versions of
    <xref target="sec:i18n" />, leading to the published result,
    and his numerous comments were always useful and contributed
    substantially to improving the quality of the final result.
  </t>
  <t>
    Peter Saint-Andre was gracious enough to read the most recent draft
    version of <xref target="sec:i18n" /> and provided some key
    insight as to the concerns of the Internationalization community.
  </t>
  <t>
    James Lentini graciously read the rewrite of
    <xref target="sec:mars" />, and his comments were
    vital in improving the quality of that effort.
  </t>
  <t>
    Rob Thurlow, Sorin Faibish, James Lentini, Bruce Fields,
    and Trond Myklebust were faithful attendants of the
    biweekly triage meeting and accepted many an action item.
  </t>
  <t>
    Bruce Fields was a good sounding board for both
    the third edge condition and courtesy locks in general.
    He was also the leading advocate of stamping out
    backport issues from <xref target="RFC5661" />.
  </t>
  <t>
    Marcel Telka was a champion of straightening out the
    difference between a lock-owner and an open-owner. He
    has also been diligent in reviewing the final document.
  </t>
  <t>
    Benjamin Kaduk reminded us that DES is dead, and Nico
    Williams helped us close the lid on the coffin.
  </t>
  <t>
    Elwyn Davies provided a very thorough and engaging
    Gen-ART review; thanks!
  </t>
</section>

</back>

</rfc>
