GANESHA-EXPORT-CONFIG(8)

πŸ’– GANESHA-EXPORT-CONFIG πŸ’–

okay bestie, welcome to ganesha-export-config β€” the NFS Ganesha Export Configuration File, aka the glow-up manual for ganesha.conf. This is the <pink>manual page for the config file itself</pink>, section 8, from the NFS-Ganesha fam. Let's get into it πŸ’…


✨ SYNOPSIS ✨

/etc/ganesha/ganesha.conf

🌸 DESCRIPTION 🌸

NFS-Ganesha pulls all its configuration tea from this one file, periodt:

/etc/ganesha/ganesha.conf

This file is where you list all the NFS-Ganesha Export block config options. It's giving main character energy, honestly.


πŸ‘‘ EXPORT PERMISSIONS πŸ‘‘

These are the "export permissions" girlies β€” they live in EXPORT_DEFAULTS {}, EXPORT {} and CLIENT {} blocks. Yes, all three. They get around πŸ’…

And all of these are dynamically updateable, no restart needed, we love a flexible queen.

  • Access_Type (enum, default None) β€” how much access we're handing out. Possible values:
    • None, RW, RO, MDONLY, MDONLY_RO
  • Protocols (enum list, default none) β€” which NFS protocol versions are allowed. Possible values:
    • 3, 4, NFS3, NFS4, V3, V4, NFSv3, NFSv4, 9P
  • Transports (enum list, values [UDP, TCP, RDMA], default [UDP, TCP]) β€” the transport layer lineup.
  • Anonymous_uid (anonid, range INT32_MIN to UINT32_MAX, default -2) β€” uid for the anonymous homie.
  • Anonymous_gid (anonid, range INT32_MIN to UINT32_MAX, default -2) β€” gid for the anonymous homie.
  • SecType (enum list, default [none, sys]) β€” security flavor. Possible values:
    • none, sys, krb5, krb5i, krb5p
  • PrivilegedPort (bool, default false) β€” require a privileged port or nah.
  • Manage_Gids (bool, default false) β€” manage the gids or nah.
  • Squash (enum, default root_sqaush) β€” the squash setting. Possible values:
    • root, root_squash, rootsquash, rootid, root_id_squash, rootidsquash, all, all_squash, allsquash, all_anomnymous, allanonymous, no_root_squash, none, noidsquash
    • iykyk: each line of defaults above are synonyms of each other 🫢
  • NFS_Commit (bool, default false) β€” nfs commit, on or off.
  • Delegations (enum, default None) β€” delegation vibes. Possible values:
    • None, read, write, readwrite, r, w, rw

πŸ¦‹ CLIENT {} πŸ¦‹

CLIENT blocks get used inside EXPORT_DEFAULTS {}, EXPORT {}, and PSEUDOFS {} blocks. They're the social butterflies of this config, fr fr.

Each CLIENT block hands you a list of clients plus the permissions granted to those clients. Together these blocks form an ordered "access control list" for the export. Here's the tea on how the fallback chain works:

If no client block matches for a particular client, then the permissions in the EXPORT {} block get used. And if any permissions aren't set between the CLIENT and the EXPORT, then the permissions set in EXPORT_DEFAULTS get used. And if they're still not set, then the code default gets used. The chain is real πŸ’€

If an EXPORT has zero CLIENT blocks, then the list of CLIENT blocks in EXPORT_DEFAULTS (if there are any) get used instead. And no matter where the CLIENT blocks came from, if the client matches none of them, then the permissions in the EXPORT get applied next.

Now, to override a restrictive default client list with "everyone", you'd have to specify a non-empty client list. Clients = "*" would do the trick ✨

Even when a CLIENT block does match a client, if a particular export permission isn't explicit in that CLIENT block, the permission specified in the EXPORT block gets used. Or if it's not specified there, from the EXPORT_DEFAULTS block. And if it's not specified there either, the permission defaults to the default code value noted in the permission option descriptions up above πŸ‘†

Heads up bestie: when the CLIENT blocks get processed on config reload, a new client access list is constructed and atomically swapped in. This lets you add, remove, and re-arrange clients, plus change the access for any given client. Slay.

CLIENT blocks use all the EXPORT PERMISSIONS options (except PSEUDOFS CLIENT blocks, which are limited to the same options the PSEUDOFS block is allowed) plus:

  • HA_Proxy_Protocol (enum, default any) β€” Possible values:
    • with_ha_proxy, without_ha_proxy, any
  • Clients (client list, empty) β€” Client list entries can take on one of the following forms. This parameter may be repeated to extend the list.
    • * β€” Match any client
    • @name β€” Netgroup name
    • x.x.x.x/y β€” IPv4 network address, IPv6 addresses are also allowed but the format is too complex to show here
    • wildcarded β€” If the string contains at least one ? or * character (and is not simply "*"), the string is used to pattern match host names. Note that [] may also be used, but the pattern MUST have at least one ? or *
    • hostname β€” Match a single client (match is by IP address, all addresses returned by getaddrinfo will match, the getaddrinfo call is made at config parsing time)
    • IP address β€” Match a single client

Any option not set in the client or export block is taken from the EXPORT_DEFAULTS block. For example, here are a few scenarios:

  1. If protocols=3 set in Export_Defaults block and protocols=4 set in CLIENT block of the export, then export can only be mounted via NFSv4 from client and not using NFSv3.
  2. If protocols=4 set in Export_Defaults, protocols=3 set in CLIENT block of the export, then that client can mount the export using only NFSv3.
  3. If protocol=3,4 set in Export_Defaults, protocol=4 set in CLIENT block of the export, then that client can mount the export using only NFSv4.

If protocol not set in CLIENT block then export options will be set using Export_Defaults protocols.


πŸŽ€ EXPORT_DEFAULTS {} πŸŽ€

All the EXPORT PERMISSIONS options plus:

  • Attr_Expiration_Time (int32, range -1 to INT32_MAX, default 60) β€” how long attributes hang around before expiring.
  • CLIENT (optional) β€” See the CLIENT {} block description. There may be any number of these. Stack 'em up πŸ’…

🌈 EXPORT_DEFAULTS { CLIENT {} } 🌈

See the CLIENT {} block description. That's the whole thing bestie, go read it.


⭐ EXPORT {} ⭐

All options below are dynamically changeable with config update unless specified below. This block may be repeated to define multiple exports. Repeat as many times as your heart desires πŸ’–

All the EXPORT_PERMISSIONS plus:

  • Export_id (required) β€” An identifier for the export, must be unique and between 0 and 65535. If Export_Id 0 is specified, Pseudo must be the root path (/).
    • Note: Export_id is not dynamic per se β€” changing it essentially removes the old export and introduces a new export.
  • Path (required) β€” The directory in the exported file system this export is rooted on (may be ignored for some FSALs). It need not be unique if Pseudo and/or Tag are specified.
    • Note that if it is not unique, and the core option mount_path_pseudo is not set true, a v3 mount using the path will ONLY be able to access the first export configured. To access other exports the Tag option would need to be used.
    • This option is NOT dynamically updateable since it fundamentally changes the export. To change the path exported, export_id should be changed also.
  • Pseudo (required v4) β€” This option specifies the position in the Pseudo Filesystem this export occupies if this is an NFS v4 export. It must be unique. By using different Pseudo options, the same Path may be exported multiple times.
    • This option is used to place the export within the NFS v4 Pseudo Filesystem. This creates a single name space for NFS v4. Clients may mount the root of the Pseudo Filesystem and navigate to exports. Note that the Path and Tag options are not at all visible to NFS v4 clients.
    • Export id 0 is automatically created to provide the root and any directories necessary to navigate to exports if there is no other export specified with Pseudo = /;. Note that if an export is specified with Pseudo = /;, it need not be export id 0. Specifying such an export with FSAL { name = PSEUDO; } may be used to create a Pseudo Filesystem with specific options. Such an export may also use other FSALs (though directories to reach exports will ONLY be automatically created on FSAL PSEUDO exports).
    • This option is dynamically changeable and changing it will move the export within the pseudo filesystem. This may be disruptive to clients. Note that if the mount_path_pseudo NFS_CORE_PARAM option is true, the NFSv3 mount path will also change (that should not be disruptive to clients that have the export mounted).
  • Tag (no default) β€” This option allows an alternative access for NFS v3 mounts. The option MUST not have a leading /. Clients may not mount subdirectories (i.e. if Tag = foo, the client may not mount foo/baz). By using different Tag options, the same Path may be exported multiple times.
    • This option is not dynamically updatable.
  • Filesystem_id (fsid, format is uint64.uint64, default unused) β€” This option allows overriding the filesystem ID provided by the underlying filesystem. Use of this option is discouraged. It will not work if VFS or GPFS is exporting a filesystem that has other filesystems mounted on sub-directories and exported with the same export.
    • This option is not dynamically updateable.
  • Read_Access_Check_Policy (enum, values [pre, post, all], default pre) β€” Whether to run permission check for read before sending the read to the FSAL, after getting the read response from the FSAL, or both before and after. This allows to optimize performance for failure flow by always checking access before sending the read, or to optimize performance for success path by storing access check result in the FSAL cache during the read and perform the access check after the read (requires the FSAL implementation to support it, so should only be used with supported FSALs). It also allow to optimize for security by running permission check both before and after.
  • MaxRead (64*1024*1024) β€” The maximum read size on this export.
  • MaxWrite (64*1024*1024) β€” The maximum write size on this export.
  • PrefRead (64*1024*1024) β€” The preferred read size on this export. Note that some older nfs client (e.g. libnfs 1.x) would not handle well for large preferred read size. If so, please try to decrease this size (usually less than 1M is suitable for older nfs client).
  • PrefWrite (64*1024*1024) β€” The preferred write size on this export. Note that some older nfs client (e.g. libnfs 1.x) would not handle well for large preferred write size. If so, please try to decrease this size (usually less than 1M is suitable for older nfs client).
  • PrefReaddir (16384) β€” The preferred readdir size on this export.
  • MaxOffsetWrite (INT64_MAX) β€” Maximum file offset that may be written. Range is 512 to UINT64_MAX.
  • MaxOffsetRead (INT64_MAX) β€” Maximum file offset that may be read. Range is 512 to UINT64_MAX.
  • DisableReaddirPlus (bool, default false) β€” turn off readdir plus or nah.
  • DisableDirChaching(bool, default false) β€” okay so bestie, if you wanna turn off directory chaching, this is your girl. Default is directory chaching enabled, and that's the good stuff β€” it makes readdir go brrr πŸ”₯. But if your export is changing a LOT (like, outside-of-NFS-workload changing) or your FSAL is out here saying "please don't use directory chaching" (looking at you, CEPH πŸ‘€), then flip this option and disable it.
  • Trust_Readdir_Negative_Cache(bool, default false) β€” that's it. That's the whole entry. No description, no vibes, just a bool chilling there πŸ’€

The following options may have limits on dynamic effect

  • UseCookieVerifier(bool, default true) β€” heads up: if you go updating UseCookieVerifier while a readdir is literally in progress, you might get unexpected behavior. So maybe don't do that mid-readdir, queen 😭
  • Disable_ACL(bool, default false) β€” Disable_ACL is processed at create_export time currently, which basically makes it a static option. So it's not really giving dynamic, it's giving set-it-and-leave-it.
  • Security_Label(bool, default false) β€” just a bool, no extra notes here πŸŽ€
  • Attr_Expiration_Time(int32, range -1 to INT32_MAX, default 60) β€” this one gets evaluated when an MDCACHE entry is created, so its dynamic effect is lowkey constrained to new entries only. Existing entries? They don't care, they already have their expiration time, periodt.
  • CLIENT (optional) β€” see the CLIENT {} block description below. You can have any number of these bad boys. ✨
  • FSAL (required) β€” see the EXPORT { FSAL {} } block. Important: the FSAL for an export can not be changed dynamically. To change the FSAL you literally have to make a whole new export. And at this time, no FSAL actually supports any updatable options. So yeah. Static. Iconic but static. πŸ’…

πŸ¦‹ EXPORT { CLIENT {} }

See the CLIENT {} block description. Simple as that, bestie.

🌸 EXPORT { FSAL {} }

NFS-Ganesha supports the following FSALs: Ceph Gluster GPFS PROXY_V3 PROXY_V4 RGW VFS XFS LUSTRE LIzardFS KVSFS

Refer to individual FSAL config file for list of config options. πŸ“‹

The FSAL blocks generally are less updatable. Just so you know.

✨ PSEUDOFS {}

This block lets you specify some options for the pseudofs root export. It's very similar to an EXPORT block, except only the following options may be specified. CLIENT blocks may be used just like an EXPORT block β€” however, they are also limited to the same options. Same is applicable to QOS_BLOCK. 🫢

It's basically a shortcut rather than having to fill out options in an EXPORT block. Note that Path, Pseudo, and Export_Id are not included, as those values will be fixed ("/" for the paths, and 0 for Export_Id). Other options that don't make sense for the pseudofs root are also not allowed. πŸ™…β€β™€οΈ

An empty PSEUDOFS {} block will produce the same default pseudofs root export as generated if no pseudofs root export is otherwise specified.

This block is most useful to override a restrictive CLIENT list in EXPORT_DEFAULTS {}.

These options will all be dynamically updateable. πŸ’–

  • Access_Type(enum, default MDONLY_RO) Possible values: None, MDONLY_RO
  • Transports(enum list, values [UDP, TCP, RDMA], default [TCP])
  • SecType(enum list, default [none, sys, krb5, krb5i, krb5p]) Possible values: none, sys, krb5, krb5i, krb5p
  • PrivilegedPort(bool, default false)
  • Export_id(uint16, range 0 to UINT16_MAX, default 0) β€” an identifier for the export, must be unique and between 0 and 65535. Ngl, Export_id is not dynamic per se β€” changing it essentially removes the old export and introduces a new export. Glow-up via full replacement, we love to see it πŸ’…
  • Filesystem_id(fsid, format is uint64.uint64, default 152.152) β€” unlike standard exports, there's no underlying filesystem to get an ID from, so this option is important. However the default value may be used, so it need not be specified. This option is not dynamically updateable.
  • DisableReaddirPlus(bool, default false)
  • Trust_Readdir_Negative_Cache(bool, default false)

The following options may have limits on dynamic effect

  • UseCookieVerifier(bool, default true) β€” again, updating UseCookieVerifier while a readdir is in progress may result in unexpected behavior. Just don't 😭

πŸ”₯ EXPORT { QOS_BLOCK {} }

This is optional: refer ManPage(8) ganesha-qos-config

πŸ”₯ PSEUDOFS { QOS_BLOCK {} }

This is optional: refer ManPage(8) ganesha-qos-config

🧚 PSEUDOFS { CLIENT {} }

See the CLIENT {} block description β€” but note that beyond the Clients and HA_Proxy_Protocol options that work as described, the other options available are as for the PSEUDOFS {} block. πŸ’«

If it is desired to override a restrictive CLIENT list in EXPORT_DEFAULTS, the following PSEUDOFS could be defined that will give all clients the default access to the pseudofs root that otherwise would have been granted if EXPORT_DEFAULTS was not used. 🌈

PSEUDOFS {

       CLIENT {
              Clients =
              *
              ;

       }

}

πŸ’¬ DISCUSSION

Okay so the EXPORT blocks define the file namespaces that are served by NFS-Ganesha. That's the whole vibe. ✨

In best practice, each underlying filesystem has a single EXPORT defining how that filesystem is to be shared. But in some cases it's desirable to sub-divide a filesystem into multiple exports. The danger when this is done is that rogue clients may be able to spoof file handles and access portions of the filesystem not intended to be accessible to that client. 🚨 So like... be careful, bestie.

Some FSALs β€” currently FSAL_VFS, FSAL_GPFS, FSAL_XFS, and FSAL_LUSTRE β€” are built to support nested filesystems, for example:

/export/fs1 /export/fs1/some/path/fs2

In this case, it's possible to create a single export that exports both filesystems. There's a lot of complexity of what can be done there. πŸŒ€

In discussions of filesystems, btrfs filesystems exported by FSAL_VFS may have subvolumes. Starting in NFS-Ganesha V4.0, FSAL_VFS treats these as separate filesystems that are integrated with all the richness of FSAL_VFS exports. ✨

Another significant FSAL from an export point of view is FSAL_PSEUDO. This is used to build glue exports to build the unified NFSv4 name space. This name space may also be used by NFSv3 by setting the NFS_CORE_PARAM option:

mount_path_pseudo = TRUE;

If no FSAL_PSEUDO export is explicitly defined, and there is no EXPORT with:

Pseudo = "/";

...then NFS-Ganesha will build a FSAL_PSEUDO EXPORT with this Pseudo Path using Export_Id = 0. This automatic EXPORT may be replaced with an explicit EXPORT which need not have Export_Id = 0 β€” it just must have Pseudo = "/" and Protocols = 4. πŸ‘‘

In building the Pseudo Filesystem, there's a subtle gotcha. Since NFSv4 clients actually mount the root of the Pseudo Filesystem and then use LOOKUP to traverse into the actual directory the sysadmin has mounted from the client, any EXPORTs from "/" to the desired EXPORT MUST have Protocols = 4 specified either in EXPORT_DEFAULTS {}, EXPORT {}, or EXPORT { CLIENT {} }. This is to assure that the client is allowed to traverse each EXPORT. No traversal, no access. 🚧

If Mount_Path_Pseudo = TRUE is being used and an export is desired to be NFSv3 only, Protocols = 3 MUST be specified in the EXPORT {} block. If Protocols is not specified in the EXPORT {} block and is only specified in an EXPORT { CLIENT {} } block, then that export will still be mounted in the Pseudo Filesystem but might not be traversable. 😬 Thus if the following two filesystems are exported:

/export/fs1 /export/fs1/some/path/fs2

And the EXPORTs look something like this:

EXPORT {
    Export_Id = 1; Path = /export/fs1; Pseudo = /export/fs1;

    FSAL {
       Name = VFS;

    }

    CLIENT {
       Clients="*"; Protocols=3;

    }

}

EXPORT {
    Export_Id = 1; Path = /export/fs1/some/path/fs2; Pseudo =
    /export/fs1/some/path/fs2;

    FSAL {
       Name = VFS;

    }

    CLIENT {
       Clients="*"; Protocols=3,4;

    }

}

NFSv4 clients will not be able to access /export/fs1/some/path/fs2. The correct way to accomplish this is:

EXPORT {
       Export_Id = 1; Path = /export/fs1; Pseudo = /export/fs1;
       Protocols=3;

    FSAL

           {      Name = VFS;

           }

}

Note that an EXPORT { CLIENT {} } block is not necessary if the default export permissions are workable. πŸŽ€

Note that in order for an EXPORT to be usable with NSFv4 it MUST either have Protocols = 4 specified in the EXPORT block, or the EXPORT block must not have the Protocols option at all such that it defaults to 3,4,9P. Note though that if it is not set and EXPORT_DEFAULTS just has Protocols = 3; then even though the export is mounted in the Pseudo Filesystem, it will not be accessible and the gotcha discussed above may be in play. πŸ’€

πŸ”„ CONFIGURATION RELOAD πŸ”„

okay so this is the part where things get ✨spicy✨ β€” bestie, you can actually hot-swap your config while NFS-Ganesha is running 😭πŸ”₯

So like, on top of the LOG {} config, the EXPORT {} config is the main config you can update while NFS-Ganesha is still up and running, and you do it by sending a SIGHUP. That's it. That's the whole trick. πŸ’…

This makes all EXPORT and EXPORT_DEFAULTS blocks get reloaded. NFS-Ganesha V4.0 and later have some genuinely significant improvements to this whole situation, because it was first introduced way back in NFS-Ganesha V2.4.0. Then V2.8.0 came in and introduced the ability to remove EXPORTs via SIGHUP configuration reload. Glow-up after glow-up, honestly. 🌈

Here's how it actually works now, and it's kind of iconic:

On SIGHUP, all the EXPORT and EXPORT_DEFAULTS blocks are re-read. There are three conditions that may occur:

  • An export may be added
  • An export may be removed
  • An export may be updated

πŸ“Œ a note on Export_Id and Path πŸ“Œ

These are the primary options that define an export. Like, the main character options. πŸ‘‘

If Export_Id is changed, the change is treated as a remove of the old Export_Id and an addition of the new Export_Id. That's just how it is, no cap.

Path can not be changed without also changing Export_Id. Not a vibe you can negotiate with, bestie. πŸ™ˆ

The Tag and Pseudo options that also contribute to the uniqueness of an EXPORT may be changed. Those ones are chill. πŸ¦‹


πŸ—‘οΈ removed exports πŸ—‘

Any removed exports are removed from the internal tables, and if they are NFSv4 exports, they get unmounted from the Pseudo Filesystem β€” which will then be re-built as if those exports had not been present. Like they never even existed. Ghosted, fr fr. πŸ’€

✨ new exports ✨

Any new exports are added to the internal tables, and if the export is an NFSv4 export, they are mounted into the Pseudo Filesystem. Welcome to the group chat, babe. 🫢

πŸŽ€ updated exports πŸŽ€

Any updated exports will be modified with the least disruption possible β€” very considerate of them, honestly.

If the Pseudo option is changed, the export is unmounted from the Pseudo Filesystem in its original location, and re-mounted in its new location. New address, same export. 🚚

Other options are updated atomically, though serially, so for a short period of time the options may be mixed between old and new. In most cases this should not cause problems β€” it's giving "we're renovating but the shop is still open." πŸ› οΈ

Notably though: the CLIENT blocks are processed to form a new access control list, and that list is atomically swapped with the old list. Clean. If the Protocols for an EXPORT are changed to include or remove NFSv4, the Pseudo Filesystem will also be updated.


⚠️ okay important one β€” note that there is no pause in operations other than a lock being taken when the client list is being swapped out. However, the export permissions are applied to an operation once.

Notably for NFSv4, this is on a PUTFH or LOOKUP which changes the Current File Handle.

As an example: if a write is in progress, having passed the permission check with the previous export permissions, the write will complete without interruption. If the write is part of an NFSv4 COMPOUND, the other operations in that COMPOUND that operate on the same file handle will also complete with the previous export permissions. Locked in. πŸ”’


🧚 EXPORT_DEFAULTS updates 🧚

An update of EXPORT_DEFAULTS changes the export options atomically. Slay.

These options are only used for those options not otherwise set in an EXPORT {} or CLIENT {} block, and are applied when export permissions are evaluated when a new file handle is encountered. Defaults stay in their lane until they're needed. πŸ’œ

🚫 the FSAL block 🚫

The FSAL { Name } may not be changed, and FSALs offer limited support for changing any options in the FSAL block. Some FSALs may validate and warn if any options in the FSAL block are changed when such a change is not supported. So like… read the warnings, bestie. They're there for a reason. πŸ™


πŸ‘€ SEE ALSO πŸ‘€

  • ganesha-config <>(8)
  • ganesha-rgw-config <>(8)
  • ganesha-vfs-config <>(8)
  • ganesha-lustre-config <>(8)
  • ganesha-xfs-config <>(8)
  • ganesha-gpfs-config <>(8)
  • ganesha-9p-config <>(8)
  • ganesha-proxy-config(8)
  • ganesha-ceph-config <>(8)
  • ganesha-qos-config <>(8)

and that's the whole page, babes!! πŸ’– this one was dated Aug 11, 2026 and it's from the GANESHA-EXPORT-CONFIG(8) manual. go forth and SIGHUP responsibly, iykyk πŸŒΈβ­πŸ‘‘

πŸ“¦ where this page comes from