blob: b17d22540017e04c55d0e8d448cbaaf9157206a0 [file] [log] [blame]
/*
* vim:noexpandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) Panasas Inc., 2011
* Author: Jim Lieb jlieb@panasas.com
*
* contributeur : Philippe DENIEL philippe.deniel@cea.fr
* Thomas LEIBOVICI thomas.leibovici@cea.fr
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* -------------
*/
/**
* @defgroup FSAL File-System Abstraction Layer
* @{
*/
/**
* @file fsal_api.h
* @author Jim Lieb <jlieb@panasas.com>
* @brief The object-oriented FSAL API
*/
#ifndef FSAL_API
#define FSAL_API
#include "fsal_types.h"
#include "fsal_pnfs.h"
#include "sal_shared.h"
#include "config_parsing.h"
#include "avltree.h"
#include "abstract_atomic.h"
/**
** Forward declarations to resolve circular dependency conflicts
*/
struct gsh_client;
struct gsh_export;
struct fsal_up_vector; /* From fsal_up.h */
struct state_t;
/**
* @page newapi New FSAL API
*
* @section structs Public and Private Data Structures
*
* Shared FSAL data structures have two definitions, one that is
* global and passed around by the core, the other private which
* included the global definition within it.
*
* All these data structures are passed back to the core with the
* global pointer and dereferenced with container_of within the FSAL
* itself like so:
*
* @code{.c}
*
* struct private_obj_handle
* {
* [private stuff]
* struct fsal_obj_handle *pub;
* }
*
* fsal_getattr(struct fsal_obj_handle handle_pub)
* {
* struct private_obj_handle *handle;
*
* handle = container_of(handle_pub,
* struct private_obj_handle, pub);
* [ do stuff ]
* }
* @endcode
*
* The @c container_of macro takes the public pointer/handle @c
* handle_pub which is indicated as the element @c pub of structure
* type @c private_obj_handle. Throughout the function, where private
* elements are dereferenced, the @c handle pointer is used. The @c
* handle_pub pointer is used in the public case.
*
* @section usage Object usage
*
* Mutex locks and reference counts are used to manage both concurrent
* usage and state. The reference counts are use to determine when
* the object is "free". Current use is for managing ref counts and
* lists. This will be expanded, though many cases are already
* handled by the locks in Cache inode.
*
* Since we cannot create objects out of thin air, there is an order
* based on one object being the "context" in which the other is
* created. In other words, a @c fsal_export is created from the @c
* fsal_module that connects it to the backing store (filesystem). The
* same applies to a @c fsal_obj_handle that only makes sense for a
* specific 'fsal_export'.
*
* When an object is created, it is returned with a reference already
* taken. The callee of the creating method must then either keep a
* persistent reference to it or @c put it back. For example, a @c
* fsal_export gets created for each export in the configuration. A
* pointer to it gets saved in @c gsh_export and it has a reference
* to reflect this. It is now safe to use it to do a @c lookup which
* will return a @c fsal_obj_handle which can then be kept in a cache
* inode entry. If we had done a @c put on the export, it could be
* freed at any point and make a @c lookup using it unsafe.
*
* In addition to a reference count, object that create other objects
* have a list of all the objects they create. This serves two
* purposes. The obvious case is to keep the object "busy" until all
* of its children are freed. Second, it provides a means to visit
* all of the objects it creates.
*
* Every object has a pointer to its parent. This is used for such
* things as managing the object list and for calling methods on the
* parent.
*
* @section versioning Versioning
*
* One intent in this API is to be able to support fsals that are built
* out-of-tree and possibly out of synch with the core of Ganesha. This
* is managed by version numbers in this file that are validated at load
* time for the fsal. There are major and minor version numbers which are
* monotonically increasing numbers ( V1 < V2 means V2 is newer).
*
* API guarantee:
*
* * If major version numbers differ, the fsal will not be loaded because
* the api has changed enough to make it unsafe.
*
* * If the major versions are equal, the minor version determines loadability.
*
* - A fsal that is older than the Ganesha core can safely load and run.
*
* - A fsal that is newer than the Ganesha core is not safe and will not
* be loaded.
*
*
* @section vector Operation Vectors
*
* Each structure carries with it an @c ops pointer. Default
* operation vectors are created at FSAL moduel initialziation time,
* and may be overridden there. Individual exports or handles may
* have different operations vectors, but they should all be derived
* from the module operations vector.
*
* This vector is used to access methods e.g.:
*
* @code{.c}
* exp_hdl->exp_ops.lookup(exp_hdl, name, ...);
* @endcode
*
* Note that exp_hdl is used to dereference the method and it is also
* *always* the first argument to the method/function. Think of it as
* the 'this' argument.
*
* @section Operation Context
*
* Protocol operations have lots of state such as user creds, the
* export currently in use etc. Rather than pass all this down the
* stack we take advantage of the design decision that a protocol
* operation runs to completion in the thread that dequeued the
* request from the RPC. All of the operation state (other than
* some intermediate results passed as function args) are pointed
* to by the thread local 'op_ctx'. This will always point to a
* valid and initialized 'struct req_op_context'.
*
* Method code can reference through 'op_ctx' e.g.
*
* @code{.c}
* if (op_ctx->req_type == 9P) { ... }
* @endcode
*
*/
/**
* @page handles File-Handles and You
*
* Overview
* ========
*
* In the FSAL, file handles can take three forms. There is the full,
* internal handle structure, compose of the @c fsal_obj_handle and
* the FSAL-private structure that contains it.
*
* There is the wire-handle, the FSAL-generated portion of the
* file handles exchanged between Ganesha and its clients through the
* FS protocol. The wire-handle should contain everything necessary
* to find and use the file even if the file has been completely
* purged from cache or Ganesha has restarted from nothing. There may
* be multiple wire-handles per @c fsal_obj_handle. The wire-handle
* is produced by the @c handle_digest method on @c fsal_obj_handle.
* The @c create_handle on @c fsal_export produces a new
* @c fsal_obj_handle from a wire-handle.
*
* There is the handle-key, the portion of the handle that contains
* all and only information that uniquely identifies the handle within
* the entire FSAL (it is insufficient if it only identifies it within
* the export or within a filesystem.) There are two functions that
* generate a handle-key, one is the @c extract_handle method on @c
* fsal_export. It is used to get the key from a wire-handle so that
* it can be looked up in the cache. The other is @c handle_to_key on
* @c fsal_obj_handle. This is used after lookup or some other
* operation that produces a @c fsal_obj_handle so that it can be
* stored or looked up in the cache.
*
* The invariant to be maintained is that given an @c fsal_obj_handle,
* fh, extract_handle(digest_handle(fh)) = handle_to_key(fh).
*
* History and Details
* ===================
*
* The terminology is confusing here. The old function names were
* kept (up to a point), but the semantics differ in ways both subtle
* and catastrophic. Making matters worse, that the first FSAL written
* was VFS, where the internal @c file_handle for the syscalls is the
* whole of the key, opaque, and syscall arg. This does not imply any
* equivalence.
*
* In the old regime, the only place available to store _anything_ was
* the handle array in @c cache_entry_t. People overloaded it with
* all kinds of rubbish as a result, and the wire-handle, the
* handle-key, and other stuff get mushed together. To sort things
* out,
*
* 1. The wire-handle opaque _must_ be enough to re-acquire the cache
* entry and its associated @c fsal_obj_handle. Other than that,
* it doesn't matter a whit. The client treats the whole protocol
* handle (including what is in the opaque) as an opaque token.
*
* 2. The purpose of the @c export_id in the protocol "handle" is to
* locate the FSAL that knows what is inside the opaque. The @c
* extract_handle is an export method for that purpose. It should
* be able to take the protocol handle opaque and translate it into
* a handle-key that @c cache_inode_get can use to find an entry.
*
* 3. cache_inode_get takes an fh_desc argument which is not a
* handle but a _key_. It is used to generate the hash and to do
* the secondary key compares. That is all it is used for. The
* end result _must_ be a cache entry and its associated
* @c fsal_obj_handle. See how @c cache_inode_get transitions to
* cache_inode_new to see how this works.
*
* 4. The @c handle_to_key method, a @c fsal_obj_handle method,
* generates a key for the cache inode hash table from the contents
* of the @c fsal_obj_handle. It is an analogue of extract_handle.
* Note where it is called to see why it is there.
*
* 5. The digest method is similar in scope but it is the inverse of
* @c extract_handle. It's job is to fill in the opaque part of a
* protocol handle. Note that it gets passed a @c gsh_buffdesc
* that describes the full opaque storage in whatever protocol
* specific structure is used. It's job is to put whatever it
* takes into the opaque so the second and third items in this list
* work.
*
* 6. Unlike the old API, a @c fsal_obj_handle is part of a FSAL
* private structure for the object. Note that there is no handle
* member of this public structure. The bits necessary to both
* create a wire handle and use a filesystem handle go into this
* private structure. You can put whatever you is required into the
* private part. Since both @c fsal_export and @c fsal_obj_handle
* have private object storage, you could even do things like have
* a container anchored in the export object that maps the
* FSAL-external handle to the filesystem data needed to talk to
* the filesystem. If you need more info to deal with handles
* differing due to hard-links, this is where you would put
* it. You would also have some other context in this private data
* to do the right thing. Just make sure there is a way to
* disambiguate the multiple cases. We do have to observe UNIX
* semantics here.
*
* The upper layers don't care about the private handle data. All
* they want is to be able to get something out from the object
* (result of a lookup) so it can find the object again later. The
* obvious case is what you describe in @c nfs[34]_FhandleToCache. These
* various methods make that happen.
*
* The linkage between a @c cache_entry_t and a @c fsal_obj_handle is
* 1-to-1 so we should really think of them as one, single object. In
* fact, there should never be a cache_entry without its associated @c
* fsal_obj_handle. The @c cache_entry_t is the cache inode part
* where things like locks and object type stuff (the AVL tree for
* dirs) are kept. The @c fsal_obj_handle part that it points to
* holds the FSAL specific part where the FD (or its backend's equiv),
* open state, and anything needed for talking to the system or
* libraries.
*/
/**
* @brief Major Version
*
* Increment this whenever any part of the existing API is changed,
* e.g. the argument list changed or a method is removed.
*
* This has been bumped to 5.0 even though the old non-support_ex API
* still exists. This is because we expect all FSALs to convert to the
* new API. The old API will be removed early in the V2.5 development
* cycle at which point we will move to 6.0.
*/
#define FSAL_MAJOR_VERSION 5
/**
* @brief Minor Version
*
* Increment this whenever a new method is appended to the m_ops vector.
* The remainder of the API is unchanged.
*
* If the major version is incremented, reset the minor to 0 (zero).
*
* If new members are appended to struct req_op_context (following its own
* rules), increment the minor version
*/
#define FSAL_MINOR_VERSION 0
/* Forward references for object methods */
struct fsal_module;
struct fsal_export;
struct fsal_obj_handle;
struct fsal_filesystem;
struct fsal_pnfs_ds;
struct fsal_pnfs_ds_ops;
struct fsal_ds_handle;
struct fsal_dsh_ops;
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
#ifndef SEEK_CUR
#define SEEK_CUR 1
#endif
#ifndef SEEK_END
#define SEEK_END 2
#endif
#ifndef SEEK_DATA
#define SEEK_DATA 3
#endif
#ifndef SEEK_HOLE
#define SEEK_HOLE 4
#endif
struct io_info {
contents io_content;
uint32_t io_advise;
bool_t io_eof;
};
struct io_hints {
offset4 offset;
length4 count;
uint32_t hints;
};
/**
* @brief request op context
*
* This is created early in the operation with the context of the
* operation. The difference between "context" and request parameters
* or arguments is that the context is derived information such as
* the resolved credentials, socket (network and client host) data
* and other bits of environment associated with the request. It gets
* passed down the call chain only as far as it needs to go for the op
* i.e. don't put it in the function/method proto "just because".
*
* The lifetime of this structure and all the data it points to is the
* operation for V2,3 and the compound for V4+. All elements and what
* they point to are invariant for the lifetime.
*
* NOTE: This is an across-the-api shared structure. It must survive with
* older consumers of its contents. Future development can change
* this struct so long as it follows the rules:
*
* 1. New elements are appended at the end, never inserted in the middle.
*
* 2. This structure _only_ contains pointers and simple scalar values.
*
* 3. Changing an already defined struct pointer is strictly not allowed.
*
* 4. This struct is always passed by reference, never by value.
*
* 5. This struct is never copied/saved.
*
* 6. Code changes are first introduced in the core. Assume the fsal
* module does not know and the code will still do the right thing.
*/
struct req_op_context {
struct user_cred *creds; /*< resolved user creds from request */
struct user_cred original_creds; /*< Saved creds */
struct group_data *caller_gdata;
gid_t *caller_garray_copy; /*< Copied garray from AUTH_SYS */
gid_t *managed_garray_copy; /*< Copied garray from managed gids */
int cred_flags; /* Various cred flags */
sockaddr_t *caller_addr; /*< IP connection info */
const uint64_t *clientid; /*< Client ID of caller, NULL if
unknown/not applicable. */
uint32_t nfs_vers; /*< NFS protocol version of request */
uint32_t nfs_minorvers; /*< NFSv4 minor version */
uint32_t req_type; /*< request_type NFS | 9P */
struct gsh_client *client; /*< client host info including stats */
struct gsh_export *ctx_export; /*< current export */
struct fsal_export *fsal_export; /*< current fsal export */
struct export_perms *export_perms; /*< Effective export perms */
nsecs_elapsed_t start_time; /*< start time of this op/request */
nsecs_elapsed_t queue_wait; /*< time in wait queue */
void *fsal_private; /*< private for FSAL use */
struct fsal_module *fsal_module; /*< current fsal module */
struct fsal_pnfs_ds *fsal_pnfs_ds; /*< current pNFS DS */
/* add new context members here */
};
/**
* @brief FSAL module methods
*/
struct fsal_ops {
/**@{*/
/**
* Base methods for loading and lifetime.
*/
/**
* @brief Unload a module
*
* This function unloads the FSL module. It should not be overridden.
*
* @param[in] fsal_hdl The module to unload.
*
* @retval 0 On success.
* @retval EBUSY If there are outstanding references or exports.
*/
int (*unload)(struct fsal_module *fsal_hdl);
/**@}*/
/**@{*/
/**
* Subclass/instance methods in each fsal
*/
/**
* @brief Initialize the configuration
*
* Given the root of the Ganesha configuration structure, initialize
* the FSAL parameters.
*
* @param[in] fsal_hdl The FSAL module
* @param[in] config_struct Parsed ganesha configuration file
* @param[out]err_type config error processing state
*
* @return FSAL status.
*/
fsal_status_t (*init_config)(struct fsal_module *fsal_hdl,
config_file_t config_struct,
struct config_error_type *err_type);
/**
* @brief Dump configuration
*
* This function dumps a human readable representation of the FSAL
* configuration.
*
* @param[in] fsal_hdl The FSAL module.
* @param[in] log_fd File descriptor to which to output the dump
*/
void (*dump_config)(struct fsal_module *fsal_hdl, int log_fd);
/**
* @brief Create a new export
*
* This function creates a new export in the FSAL using the supplied
* path and options. The function is expected to allocate its own
* export (the full, private structure). It must then initialize the
* public portion like so:
*
* @code{.c}
* fsal_export_init(&private_export_handle->pub);
* @endcode
*
* After doing other private initialization, it must attach the export
* to the module, like so:
*
*
* @code{.c}
* fsal_attach_export(fsal_hdl,
* &private_export->pub.exports);
*
* @endcode
*
* And create the parent link with:
*
* @code{.c}
* private_export->pub.fsal = fsal_hdl;
* @endcode
*
* @note This seems like something that fsal_attach_export should
* do. -- ACE.
*
* @param[in] fsal_hdl FSAL module
* @param[in] parse_node opaque pointer to parse tree node for
* export options to be passed to
* load_config_from_node
* @param[out] err_type config proocessing error reporting
* @param[in] up_ops Upcall ops
*
* @return FSAL status.
*/
fsal_status_t (*create_export)(struct fsal_module *fsal_hdl,
void *parse_node,
struct config_error_type *err_type,
const struct fsal_up_vector *up_ops);
/**
* @brief Minimal emergency cleanup on error
*
* This method is called only in the event of a catastrophic
* failure. Currently, it will be called if some detail of the orderly
* shutdown fails, so that FSALs will have the opportunity to leave
* their underlying filesystems in a consistent state. It may at some
* later time be called in the event of a crash. The majority of FSALs
* will have no need to implement this call and should not do so.
*
* This function should, if implemented:
*
* 1. Do the bare minimum necessary to allow access to the each
* underlying filesystem it serves. (the equivalent of a clean
* unmount, so that a future instance of Ganesha or other tool can
* mount the filesystem without difficulty.) How the FSAL defines
* 'underlying filesystem' is FSAL specific. The FSAL handle itself
* has a list of attached exports and that can be traversed if
* suitable.
*
* 2. It /must not/ take any mutices, reader-writer locks, spinlocks,
* sleep on any condition variables, or similar. Since other threads
* may have crashed or been cancelled, locks may be left held,
* overwritten with random garbage, or be similarly awful. The point
* is to shut down cleanly, and you can't shut down cleanly if you're
* hung. This does not create a race condition, since other threads in
* Ganesha will have been cancelled by this point.
*
* 3. If it is at all possible to avoid, do not allocate memory on the
* heap or use other services that require the user space to be in a
* consistent state. If this is called from a crash handler, the Arena
* may be corrupt. If you know that your FSAL *will* require memory,
* you should either allocate it statically, or dynamically at
* initialization time.
*/
void (*emergency_cleanup)(void);
/**
* pNFS functions
*/
/**
* @brief Get information about a pNFS device
*
* When this function is called, the FSAL should write device
* information to the @c da_addr_body stream.
*
* @param[in] fsal_hdl FSAL module
* @param[out] da_addr_body An XDR stream to which the FSAL is to
* write the layout type-specific information
* corresponding to the deviceid.
* @param[in] type The type of layout that specified the
* device
* @param[in] deviceid The device to look up
*
* @return Valid error codes in RFC 5661, p. 365.
*/
nfsstat4(*getdeviceinfo)(struct fsal_module *fsal_hdl,
XDR * da_addr_body,
const layouttype4 type,
const struct pnfs_deviceid *deviceid);
/**
* @brief Max Size of the buffer needed for da_addr_body in getdeviceinfo
*
* This function sets policy for XDR buffer allocation in getdeviceinfo.
* If FSAL has a const size, just return it here. If it is dependent on
* what the client can take return ~0UL. In any case the buffer allocated will
* not be bigger than client's requested maximum.
*
* @param[in] exp_hdl Filesystem to interrogate
*
* @return Max size of the buffer needed for a da_addr_body
*/
size_t (*fs_da_addr_size)(struct fsal_module *fsal_hdl);
/**
* @brief Create a FSAL pNFS data server
*
* @param[in] fsal_hdl FSAL module
* @param[in] parse_node opaque pointer to parse tree node for
* export options to be passed to
* load_config_from_node
* @param[out] handle FSAL pNFS DS
*
* @return FSAL status.
*/
fsal_status_t (*fsal_pnfs_ds)(struct fsal_module *const fsal_hdl,
void *parse_node,
struct fsal_pnfs_ds **const handle);
/**
* @brief Initialize FSAL specific values for pNFS data server
*
* @param[in] ops FSAL pNFS Data Server operations vector
*/
void (*fsal_pnfs_ds_ops)(struct fsal_pnfs_ds_ops *ops);
/**
* @brief Indicate support for extended operations.
*
* @retval true if extended operations are supported.
*/
bool (*support_ex)(struct fsal_obj_handle *obj);
/**@}*/
};
/**
* @brief Export operations
*/
struct export_ops {
/**@{*/
/**
* Export information
*/
/**
* @brief Get the name of the FSAL provisioning the export
*
* This function is used to find the name of the ultimate FSAL providing the
* filesystem. If FSALs are stacked, then the super-FSAL may want to pass this
* through to the sub-FSAL to get the name, or add the sub-FSAL's name onto it's
* own name.
*
* @param[in] exp_hdl The export to query.
* @return Name of FSAL provisioning export
*/
const char *(*get_name)(struct fsal_export *exp_hdl);
/**@}*/
/**@{*/
/**
* Export lifecycle management.
*/
/**
* @brief Clean up an export when it's unexported
*
* This function is called when the export is unexported. It should release any
* working data that is not necessary when unexported, but not free the export
* itself, as there are still references to it.
*
* @param[in] exp_hdl The export to unexport.
* @param[in] root_obj The root object of the export
*/
void (*unexport)(struct fsal_export *exp_hdl,
struct fsal_obj_handle *root_obj);
/**
* @brief Finalize an export
*
* This function is called as part of cleanup when the last reference to
* an export is released and it is no longer part of the list. It
* should clean up all private resources and destroy the object.
*
* @param[in] exp_hdl The export to release.
*/
void (*release)(struct fsal_export *exp_hdl);
/**@}*/
/**@{*/
/**
* Create an object handles within this export
*/
/**
* @brief Look up a path
*
* This function looks up a path within the export, it is typically
* used to get a handle for the root directory of the export.
*
* The caller will set the request_mask in attrs_out to indicate the attributes
* of interest. ATTR_ACL SHOULD NOT be requested and need not be provided. If
* not all the requested attributes can be provided, this method MUST return
* an error unless the ATTR_RDATTR_ERR bit was set in the request_mask.
*
* Since this method instantiates a new fsal_obj_handle, it will be forced
* to fetch at least some attributes in order to even know what the object
* type is (as well as it's fileid and fsid). For this reason, the operation
* as a whole can be expected to fail if the attributes were not able to be
* fetched.
*
* @param[in] exp_hdl The export in which to look up
* @param[in] path The path to look up
* @param[out] handle The object found
* @param[in,out] attrs_out Optional attributes for newly created object
*
* @note On success, @a handle has been ref'd
*
* @return FSAL status.
*/
fsal_status_t (*lookup_path)(struct fsal_export *exp_hdl,
const char *path,
struct fsal_obj_handle **handle,
struct attrlist *attrs_out);
/**
* @brief Look up a junction
*
* This function returns a handle for the directory behind a junction
* object.
*
* @deprecated This function is not implemented by any FSAL nor is it
* called. It exists here as a placeholder for implementation in 2.1
* as part of the PseudoFSAL work. Its argument structure will almost
* certainly change.
*
* @param[in] exp_hdl Export in which to look up
* @param[in] junction The junction object
* @param[out] handle The underlying directory handle
*
* @return FSAL status.
*/
fsal_status_t (*lookup_junction)(struct fsal_export *exp_hdl,
struct fsal_obj_handle *junction,
struct fsal_obj_handle **handle);
/**
* @brief Extract an opaque handle
*
* This function extracts a "key" handle from a "wire" handle. That
* is, when given a handle as passed to a client, this method will
* extract the unique bits used to index the inode cache.
*
* @param[in] exp_hdl Export in which to look up handle
* @param[in] in_type Protocol through which buffer was received. One
* special case, FSAL_DIGEST_SIZEOF, simply
* requests that fh_desc.len be set to the proper
* size of a wire handle.
* @param[in,out] fh_desc Buffer descriptor. The address of the
* buffer is given in @c fh_desc->buf and must
* not be changed. @c fh_desc->len is the
* length of the data contained in the buffer,
* and @c fh_desc->maxlen is the total size of
* the buffer, should the FSAL wish to write a
* longer handle. @c fh_desc->len must be
* updated to the correct size.
*
* @return FSAL type.
*/
fsal_status_t (*extract_handle)(struct fsal_export *exp_hdl,
fsal_digesttype_t in_type,
struct gsh_buffdesc *fh_desc,
int flags);
/**
* @brief Create a FSAL object handle from a wire handle
*
* This function creates a FSAL object handle from a client supplied
* "wire" handle (when an object is no longer in cache but the client
* still remembers the nandle).
*
* The caller will set the request_mask in attrs_out to indicate the attributes
* of interest. ATTR_ACL SHOULD NOT be requested and need not be provided. If
* not all the requested attributes can be provided, this method MUST return
* an error unless the ATTR_RDATTR_ERR bit was set in the request_mask.
*
* Since this method instantiates a new fsal_obj_handle, it will be forced
* to fetch at least some attributes in order to even know what the object
* type is (as well as it's fileid and fsid). For this reason, the operation
* as a whole can be expected to fail if the attributes were not able to be
* fetched.
*
* @param[in] exp_hdl The export in which to create the handle
* @param[in] hdl_desc Buffer descriptor for the "wire" handle
* @param[out] handle FSAL object handle
* @param[in,out] attrs_out Optional attributes for newly created object
*
* @note On success, @a handle has been ref'd
*
* @return FSAL status.
*/
fsal_status_t (*create_handle)(struct fsal_export *exp_hdl,
struct gsh_buffdesc *hdl_desc,
struct fsal_obj_handle **handle,
struct attrlist *attrs_out);
/**@}*/
/**@{*/
/**
* Statistics and configuration for this filesystem
*/
/**
* @brief Get filesystem statistics
*
* This function gets information on inodes and space in use and free
* for a filesystem. See @c fsal_dynamicinfo_t for details of what to
* fill out.
*
* @param[in] exp_hdl Export handle to interrogate
* @param[in] obj_hdl Directory
* @param[out] info Buffer to fill with information
*
* @retval FSAL status.
*/
fsal_status_t (*get_fs_dynamic_info)(struct fsal_export *exp_hdl,
struct fsal_obj_handle *obj_hdl,
fsal_dynamicfsinfo_t *info);
/**
* @brief Export feature test
*
* This function checks whether a feature is supported on this
* filesystem. The features that can be interrogated are given in the
* @c fsal_fsinfo_options_t enumeration.
*
* @param[in] exp_hdl The export to interrogate
* @param[in] option The feature to query
*
* @retval true if the feature is supported.
* @retval false if the feature is unsupported or unknown.
*/
bool (*fs_supports)(struct fsal_export *exp_hdl,
fsal_fsinfo_options_t option);
/**
* @brief Get the greatest file size supported
*
* @param[in] exp_hdl Filesystem to interrogate
*
* @return Greatest file size supported.
*/
uint64_t (*fs_maxfilesize)(struct fsal_export *exp_hdl);
/**
* @brief Get the greatest read size supported
*
* @param[in] exp_hdl Filesystem to interrogate
*
* @return Greatest read size supported.
*/
uint32_t (*fs_maxread)(struct fsal_export *exp_hdl);
/**
* @brief Get the greatest write size supported
*
* @param[in] exp_hdl Filesystem to interrogate
*
* @return Greatest write size supported.
*/
uint32_t (*fs_maxwrite)(struct fsal_export *exp_hdl);
/**
* @brief Get the greatest link count supported
*
* @param[in] exp_hdl Filesystem to interrogate
*
* @return Greatest link count supported.
*/
uint32_t (*fs_maxlink)(struct fsal_export *exp_hdl);
/**
* @brief Get the greatest name length supported
*
* @param[in] exp_hdl Filesystem to interrogate
*
* @return Greatest name length supported.
*/
uint32_t (*fs_maxnamelen)(struct fsal_export *exp_hdl);
/**
* @brief Get the greatest path length supported
*
* @param[in] exp_hdl Filesystem to interrogate
*
* @return Greatest path length supported.
*/
uint32_t (*fs_maxpathlen)(struct fsal_export *exp_hdl);
/**
* @brief Get the lease time for this filesystem
*
* @note Currently this value has no effect, with lease time being
* configured globally for all filesystems at once.
*
* @param[in] exp_hdl Filesystem to interrogate
*
* @return Lease time.
*/
struct timespec (*fs_lease_time)(struct fsal_export *exp_hdl);
/**
* @brief Get supported ACL types
*
* This function returns a bitmask indicating whether it supports
* ALLOW, DENY, neither, or both types of ACL.
*
* @note Could someone with more ACL support tell me if this is sane?
* Is it legitimate for an FSAL supporting ACLs to support just ALLOW
* or just DENY without supporting the other? It seems fishy to
* me. -- ACE
*
* @param[in] exp_hdl Filesystem to interrogate
*
* @return supported ACL types.
*/
fsal_aclsupp_t (*fs_acl_support)(struct fsal_export *exp_hdl);
/**
* @brief Get supported attributes
*
* This function returns a list of all attributes that this FSAL will
* support. Be aware that this is specifically the attributes in
* struct attrlist, other NFS attributes (fileid and so forth) are
* supported through other means.
*
* @param[in] exp_hdl Filesystem to interrogate
*
* @return supported attributes.
*/
attrmask_t (*fs_supported_attrs)(struct fsal_export *exp_hdl);
/**
* @brief Get umask applied to created files
*
* @note This seems fishy to me. Is this actually supported properly?
* And is it something we want the FSAL being involved in? We already
* have the functions in Protocol/NFS specifying a default mode. -- ACE
*
* @param[in] exp_hdl Filesystem to interrogate
*
* @return creation umask.
*/
uint32_t (*fs_umask)(struct fsal_export *exp_hdl);
/**
* @brief Get permissions applied to names attributes
*
* @note This doesn't make sense to me as an export-level parameter.
* Permissions on named attributes could reasonably vary with
* permission and ownership of the associated file, and some
* attributes may be read/write while others are read-only. -- ACE
*
* @param[in] exp_hdl Filesystem to interrogate
*
* @return permissions on named attributes.
*/
uint32_t (*fs_xattr_access_rights)(struct fsal_export *exp_hdl);
/**@}*/
/**@{*/
/**
* Quotas are managed at the file system (export) level. Someone who
* uses quotas, please look over these comments to check/expand them.
*/
/**
* @brief Check if quotas allow an operation
*
* This function checks to see if a user has overrun a quota and
* should be disallowed from performing an operation that would
* consume blocks or inodes.
*
* @param[in] exp_hdl The export to interrogate
* @param[in] filepath The path within the export to check
* @param[in] quota_type Whether we are checking inodes or blocks
*
* @return FSAL types.
*/
fsal_status_t (*check_quota)(struct fsal_export *exp_hdl,
const char *filepath, int quota_type);
/**
* @brief Get a user's quota
*
* This function retrieves a given user's quota.
*
* @param[in] exp_hdl The export to interrogate
* @param[in] filepath The path within the export to check
* @param[in] quota_type Whether we are checking inodes or blocks
* @param[in] quota_id Id for which quota is set
* @param[out] quota The user's quota
*
* @return FSAL types.
*/
fsal_status_t (*get_quota)(struct fsal_export *exp_hdl,
const char *filepath, int quota_type,
int quota_id,
fsal_quota_t *quota);
/**
* @brief Set a user's quota
*
* This function sets a user's quota.
*
* @param[in] exp_hdl The export to interrogate
* @param[in] filepath The path within the export to check
* @param[in] quota_type Whether we are checking inodes or blocks
* @param[in] quota_id Id for which quota is set
* @param[in] quota The values to set for the quota
* @param[out] resquota New values set (optional)
*
* @return FSAL types.
*/
fsal_status_t (*set_quota)(struct fsal_export *exp_hdl,
const char *filepath, int quota_type,
int quota_id,
fsal_quota_t *quota,
fsal_quota_t *resquota);
/**@}*/
/**@{*/
/**
* pNFS functions
*/
/**
* @brief Get list of available devices
*
* This function should populate calls @c cb @c values representing the
* low quad of deviceids it wishes to make the available to the
* caller. it should continue calling @c cb until @c cb returns false
* or it runs out of deviceids to make available. If @c cb returns
* false, it should assume that @c cb has not stored the most recent
* deviceid and set @c res->cookie to a value that will begin witht he
* most recently provided.
*
* If it wishes to return no deviceids, it may set @c res->eof to true
* without calling @c cb at all.
*
* @param[in] exp_hdl Export handle
* @param[in] type Type of layout to get devices for
* @param[in] cb Function taking device ID halves
* @param[in,out] res In/out and output arguments of the function
*
* @return Valid error codes in RFC 5661, pp. 365-6.
*/
nfsstat4(*getdevicelist)(struct fsal_export *exp_hdl,
layouttype4 type, void *opaque,
bool (*cb)(void *opaque, const uint64_t id),
struct fsal_getdevicelist_res *res);
/**
* @brief Get layout types supported by export
*
* This function is the handler of the NFS4.1 FATTR4_FS_LAYOUT_TYPES file
* attribute. (See RFC)
*
* @param[in] exp_hdl Filesystem to interrogate
* @param[out] count Number of layout types in array
* @param[out] types Static array of layout types that must not be
* freed or modified and must not be dereferenced
* after export reference is relinquished
*/
void (*fs_layouttypes)(struct fsal_export *exp_hdl, int32_t *count,
const layouttype4 **types);
/**
* @brief Get layout block size for export
*
* This function is the handler of the NFS4.1 FATTR4_LAYOUT_BLKSIZE f-attribute.
*
* This is the preferred read/write block size. Clients are requested
* (but don't have to) read and write in multiples.
*
* NOTE: The linux client only asks for this in blocks-layout, where this is the
* filesystem wide block-size. (Minimum write size and alignment)
*
* @param[in] exp_hdl Filesystem to interrogate
*
* @return The preferred layout block size.
*/
uint32_t (*fs_layout_blocksize)(struct fsal_export *exp_hdl);
/**
* @brief Maximum number of segments we will use
*
* This function returns the maximum number of segments that will be
* used to construct the response to any single layoutget call. Bear
* in mind that current clients only support 1 segment.
*
* @param[in] exp_hdl Filesystem to interrogate
*
* @return The Maximum number of layout segments in a campound layoutget.
*/
uint32_t (*fs_maximum_segments)(struct fsal_export *exp_hdl);
/**
* @brief Size of the buffer needed for loc_body at layoutget
*
* This function sets policy for XDR buffer allocation in layoutget vector
* below. If FSAL has a const size, just return it here. If it is dependent on
* what the client can take return ~0UL. In any case the buffer allocated will
* not be bigger than client's requested maximum.
*
* @param[in] exp_hdl Filesystem to interrogate
*
* @return Max size of the buffer needed for a loc_body
*/
size_t (*fs_loc_body_size)(struct fsal_export *exp_hdl);
/**
* @brief Get write verifier
*
* This function is called by write and commit to match the commit verifier
* with the one returned on write.
*
* @param[in] exp_hdl Export to query
* @param[in,out] verf_desc Address and length of verifier
*/
void (*get_write_verifier)(struct fsal_export *exp_hdl,
struct gsh_buffdesc *verf_desc);
/**@}*/
/**
* @brief Allocate a state_t structure
*
* Note that this is not expected to fail since memory allocation is
* expected to abort on failure.
*
* @param[in] exp_hdl Export state_t will be associated with
* @param[in] state_type Type of state to allocate
* @param[in] related_state Related state if appropriate
*
* @returns a state structure.
*/
struct state_t *(*alloc_state)(struct fsal_export *exp_hdl,
enum state_type state_type,
struct state_t *related_state);
/**
* @brief Free a state_t structure
*
* @param[in] exp_hdl Export state_t is associated with
* @param[in] state state_t structure to free.
*
* @returns NULL on failure otherwise a state structure.
*/
void (*free_state)(struct fsal_export *exp_hdl, struct state_t *state);
};
/**
* @brief Filesystem operations
*/
typedef int (*claim_filesystem_cb)(struct fsal_filesystem *fs,
struct fsal_export *exp);
typedef void (*unclaim_filesystem_cb)(struct fsal_filesystem *fs);
enum fsid_type {
FSID_NO_TYPE,
FSID_ONE_UINT64,
FSID_MAJOR_64,
FSID_TWO_UINT64,
FSID_TWO_UINT32,
FSID_DEVICE
};
static inline uint64_t squash_fsid(const struct fsal_fsid__ *fsid)
{
return fsid->major ^ (fsid->minor << 32 | fsid->minor >> 32);
}
static inline int sizeof_fsid(enum fsid_type type)
{
switch (type) {
case FSID_NO_TYPE:
return 0;
case FSID_ONE_UINT64:
case FSID_MAJOR_64:
return sizeof(uint64_t);
case FSID_TWO_UINT64:
return 2 * sizeof(uint64_t);
case FSID_TWO_UINT32:
case FSID_DEVICE:
return 2 * sizeof(uint32_t);
}
return -1;
}
/**
* @brief Directory cookie
*/
typedef uint64_t fsal_cookie_t;
/**
* @brief Callback to provide readdir caller with each directory entry
*
* @param[in] name The name of the entry
* @param[in] obj The fsal_obj_handle describing the entry
* @param[in] attrs The requested attribues for the entry (see readdir
* attrmask parameter)
* @param[in] dir_state Opaque pointer to be passed to callback
* @param[in] cookie An FSAL generated cookie for the entry
*
* @retval true if more entries are required
* @retval false if no more entries are required (and the current one
* has not been consumed)
*/
typedef bool (*fsal_readdir_cb)(const char *name, struct fsal_obj_handle *obj,
struct attrlist *attrs,
void *dir_state, fsal_cookie_t cookie);
/**
* @brief FSAL object operations vector
*/
struct fsal_obj_ops {
/**@{*/
/**
* Lifecycle management
*/
/**
* @brief Get a reference to a handle
*
* Refcounting is required for all FSALs. An FSAL that will have FSAL_MDCACHE
* stacked on top need not handle this as FSAL_MDCACHE will handle it.
*
* @param[in] obj_hdl Handle to release
*/
void (*get_ref)(struct fsal_obj_handle *obj_hdl);
/**
* @brief Put a reference to a handle
*
* Refcounting is required for all FSALs. An FSAL that will have FSAL_MDCACHE
* stacked on top need not handle this as FSAL_MDCACHE will handle it.
*
* @param[in] obj_hdl Handle to release
*/
void (*put_ref)(struct fsal_obj_handle *obj_hdl);
/**
* @brief Clean up a filehandle
*
* This function cleans up private resources associated with a
* filehandle and deallocates it. Implement this method or you will
* leak. Refcount (if used) should be 1
*
* @param[in] obj_hdl Handle to release
*/
void (*release)(struct fsal_obj_handle *obj_hdl);
/**
* @brief Merge a duplicate handle with an original handle
*
* This function is used if an upper layer detects that a duplicate
* object handle has been created. It allows the FSAL to merge anything
* from the duplicate back into the original.
*
* The caller must release the object (the caller may have to close
* files if the merge is unsuccessful).
*
* @param[in] orig_hdl Original handle
* @param[in] dupe_hdl Handle to merge into original
*
* @return FSAL status.
*
*/
fsal_status_t (*merge)(struct fsal_obj_handle *orig_hdl,
struct fsal_obj_handle *dupe_hdl);
/**@}*/
/**@{*/
/**
* Directory operations
*/
/**
* @brief Look up a filename
*
* This function looks up the given name in the supplied directory.
*
* @note The old version of the FSAL had a special case for this
* function, such that if the directory handle and path were both
* NULL, a handle to the root of the export was returned. This
* special case is no longer supported and should not be implemented.
*
* The caller will set the request_mask in attrs_out to indicate the attributes
* of interest. ATTR_ACL SHOULD NOT be requested and need not be provided. If
* not all the requested attributes can be provided, this method MUST return
* an error unless the ATTR_RDATTR_ERR bit was set in the request_mask.
*
* Since this method instantiates a new fsal_obj_handle, it will be forced
* to fetch at least some attributes in order to even know what the object
* type is (as well as it's fileid and fsid). For this reason, the operation
* as a whole can be expected to fail if the attributes were not able to be
* fetched.
*
* @param[in] dir_hdl Directory to search
* @param[in] path Name to look up
* @param[out] handle Object found
* @param[in,out] attrs_out Optional attributes for newly created object
*
* @note On success, @a handle has been ref'd
*
* @return FSAL status.
*/
fsal_status_t (*lookup)(struct fsal_obj_handle *dir_hdl,
const char *path,
struct fsal_obj_handle **handle,
struct attrlist *attrs_out);
/**
* @brief Read a directory
*
* This function reads directory entries from the FSAL and supplies
* them to a callback.
*
* @param[in] dir_hdl Directory to read
* @param[in] whence Point at which to start reading. NULL to
* start at beginning.
* @param[in] dir_state Opaque pointer to be passed to callback
* @param[in] cb Callback to receive names
* @param[in] attrmask Indicate which attributes the caller is interested in
* @param[out] eof true if the last entry was reached
*
* @return FSAL status.
*/
fsal_status_t (*readdir)(struct fsal_obj_handle *dir_hdl,
fsal_cookie_t *whence,
void *dir_state,
fsal_readdir_cb cb,
attrmask_t attrmask,
bool *eof);
/**@}*/
/**@{*/
/**
* Creation operations
*/
/**
* @brief Create a regular file
*
* This function creates a new regular file.
*
* This method is obsolete with support_ex.
*
* The caller is expected to invoke fsal_release_attrs to release any
* resources held by the set attributes. The FSAL layer MAY have added an
* inherited ACL.
*
* The caller will set the request_mask in attrs_out to indicate the attributes
* of interest. ATTR_ACL SHOULD NOT be requested and need not be provided. If
* not all the requested attributes can be provided, this method MUST return
* an error unless the ATTR_RDATTR_ERR bit was set in the request_mask.
*
* Since this method instantiates a new fsal_obj_handle, it will be forced
* to fetch at least some attributes in order to even know what the object
* type is (as well as it's fileid and fsid). For this reason, the operation
* as a whole can be expected to fail if the attributes were not able to be
* fetched.
*
* @param[in] dir_hdl Directory in which to create the file
* @param[in] name Name of file to create
* @param[in] attrs_in Attributes to set on newly created object
* @param[out] new_obj Newly created object
* @param[in,out] attrs_out Optional attributes for newly created object
*
* @note On success, @a new_obj has been ref'd
*
* @return FSAL status.
*/
fsal_status_t (*create)(struct fsal_obj_handle *dir_hdl,
const char *name, struct attrlist *attrs_in,
struct fsal_obj_handle **new_obj,
struct attrlist *attrs_out);
/**
* @brief Create a directory
*
* This function creates a new directory.
*
* For support_ex, this method will handle attribute setting. The caller
* MUST include the mode attribute and SHOULD NOT include the owner or
* group attributes if they are the same as the op_ctx->cred.
*
* The caller is expected to invoke fsal_release_attrs to release any
* resources held by the set attributes. The FSAL layer MAY have added an
* inherited ACL.
*
* The caller will set the request_mask in attrs_out to indicate the attributes
* of interest. ATTR_ACL SHOULD NOT be requested and need not be provided. If
* not all the requested attributes can be provided, this method MUST return
* an error unless the ATTR_RDATTR_ERR bit was set in the request_mask.
*
* Since this method instantiates a new fsal_obj_handle, it will be forced
* to fetch at least some attributes in order to even know what the object
* type is (as well as it's fileid and fsid). For this reason, the operation
* as a whole can be expected to fail if the attributes were not able to be
* fetched.
*
* @param[in] dir_hdl Directory in which to create the directory
* @param[in] name Name of directory to create
* @param[in] attrs_in Attributes to set on newly created object
* @param[out] new_obj Newly created object
* @param[in,out] attrs_out Optional attributes for newly created object
*
* @note On success, @a new_obj has been ref'd
*
* @return FSAL status.
*/
fsal_status_t (*mkdir)(struct fsal_obj_handle *dir_hdl,
const char *name, struct attrlist *attrs_in,
struct fsal_obj_handle **new_obj,
struct attrlist *attrs_out);
/**
* @brief Create a special file
*
* This function creates a new special file.
*
* For support_ex, this method will handle attribute setting. The caller
* MUST include the mode attribute and SHOULD NOT include the owner or
* group attributes if they are the same as the op_ctx->cred.
*
* If the node type has rawdev info, then @a attrs_in MUST have the rawdev field
* set.
*
* The caller is expected to invoke fsal_release_attrs to release any
* resources held by the set attributes. The FSAL layer MAY have added an
* inherited ACL.
*
* The caller will set the request_mask in attrs_out to indicate the attributes
* of interest. ATTR_ACL SHOULD NOT be requested and need not be provided. If
* not all the requested attributes can be provided, this method MUST return
* an error unless the ATTR_RDATTR_ERR bit was set in the request_mask.
*
* Since this method instantiates a new fsal_obj_handle, it will be forced
* to fetch at least some attributes in order to even know what the object
* type is (as well as it's fileid and fsid). For this reason, the operation
* as a whole can be expected to fail if the attributes were not able to be
* fetched.
*
* @param[in] dir_hdl Directory in which to create the object
* @param[in] name Name of object to create
* @param[in] nodetype Type of special file to create
* @param[in] attrs_in Attributes to set on newly created object
* @param[out] new_obj Newly created object
* @param[in,out] attrs_out Optional attributes for newly created object
*
* @note On success, @a new_obj has been ref'd
*
* @return FSAL status.
*/
fsal_status_t (*mknode)(struct fsal_obj_handle *dir_hdl,
const char *name,
object_file_type_t nodetype,
struct attrlist *attrs_in,
struct fsal_obj_handle **new_obj,
struct attrlist *attrs_out);
/**
* @brief Create a symbolic link
*
* This function creates a new symbolic link.
*
* For support_ex, this method will handle attribute setting. The caller
* MUST include the mode attribute and SHOULD NOT include the owner or
* group attributes if they are the same as the op_ctx->cred.
*
* The caller is expected to invoke fsal_release_attrs to release any
* resources held by the set attributes. The FSAL layer MAY have added an
* inherited ACL.
*
* The caller will set the request_mask in attrs_out to indicate the attributes
* of interest. ATTR_ACL SHOULD NOT be requested and need not be provided. If
* not all the requested attributes can be provided, this method MUST return
* an error unless the ATTR_RDATTR_ERR bit was set in the request_mask.
*
* Since this method instantiates a new fsal_obj_handle, it will be forced
* to fetch at least some attributes in order to even know what the object
* type is (as well as it's fileid and fsid). For this reason, the operation
* as a whole can be expected to fail if the attributes were not able to be
* fetched.
*
* @param[in] dir_hdl Directory in which to create the object
* @param[in] name Name of object to create
* @param[in] link_path Content of symbolic link
* @param[in] attrs_in Attributes to set on newly created object
* @param[out] new_obj Newly created object
* @param[in,out] attrs_out Optional attributes for newly created object
*
* @note On success, @a new_obj has been ref'd
*
* @return FSAL status.
*/
fsal_status_t (*symlink)(struct fsal_obj_handle *dir_hdl,
const char *name,
const char *link_path,
struct attrlist *attrs_in,
struct fsal_obj_handle **new_obj,
struct attrlist *attrs_out);
/**@}*/
/**@{*/
/**
* File object operations
*/
/**
* @brief Read the content of a link
*
* This function reads the content of a symbolic link. The FSAL will
* allocate a buffer and store its address and the link length in the
* link_content gsh_buffdesc. The caller *must* free this buffer with
* gsh_free.
*
* The symlink content passed back *must* be null terminated and the
* length indicated in the buffer description *must* include the
* terminator.
*
* @param[in] obj_hdl Link to read
* @param[out] link_content Buffdesc to which the FSAL will store
* the address of the buffer holding the
* link and the link length.
* @param[out] refresh true if the content are to be retrieved
* from the underlying filesystem rather
* than cache
*
* @return FSAL status.
*/
fsal_status_t (*readlink)(struct fsal_obj_handle *obj_hdl,
struct gsh_buffdesc *link_content,
bool refresh);
/**
* @brief Check access for a given user against a given object
*
* This function checks whether a given user is allowed to perform the
* specified operations against the supplied file. The goal is to
* allow filesystem specific semantics to be applied to cached
* metadata.
*
* This method must read attributes and/or get them from a cache.
*
* @param[in] obj_hdl Handle to check
* @param[in] access_type Access requested
* @param[out] allowed Returned access that could be granted
* @param[out] denied Returned access that would be granted
* @param[in] owner_skip Skip test if op_ctx->creds is owner
*
* @return FSAL status.
*/
fsal_status_t (*test_access)(struct fsal_obj_handle *obj_hdl,
fsal_accessflags_t access_type,
fsal_accessflags_t *allowed,
fsal_accessflags_t *denied,
bool owner_skip);
/**
* @brief Get attributes
*
* This function fetches the attributes for the object. The attributes
* requested in the mask are copied out (though other attributes might
* be copied out).
*
* The caller will set the request_mask in attrs_out to indicate the attributes
* of interest. ATTR_ACL SHOULD NOT be requested and need not be provided. If
* not all the requested attributes can be provided, this method MUST return
* an error unless the ATTR_RDATTR_ERR bit was set in the request_mask.
*
* The caller MUST call fsal_release_attrs when done with the copied
* out attributes. This will release any attributes that might take
* additional memory.
*
* @param[in] obj_hdl Object to query
* @param[out] attrs_out Attribute list for file
*
* @return FSAL status.
*/
fsal_status_t (*getattrs)(struct fsal_obj_handle *obj_hdl,
struct attrlist *attrs_out);
/**
* @brief Set attributes on an object
*
* This function sets attributes on an object. Which attributes are
* set is determined by @c attrib_set->mask.
*
* The caller is expected to invoke fsal_release_attrs to release any
* resources held by the set attributes. The FSAL layer MAY have added an
* inherited ACL.
*
* Due to differences between protocols (9P, NFSv3 and NFSv4) and backends,
* FSALs may ignore request for modifying the ctime attribute without returning
* EINVAL or any error status.
*
* @param[in] obj_hdl The object to modify
* @param[in] attrib_set Attributes to set
*
* @return FSAL status.
*/
fsal_status_t (*setattrs)(struct fsal_obj_handle *obj_hdl,
struct attrlist *attrib_set);
/**
* @brief Create a new link
*
* This function creates a new name for an existing object.
*
* @param[in] obj_hdl Object to be linked to
* @param[in] destdir_hdl Directory in which to create the link
* @param[in] name Name for link
*
* @return FSAL status
*/
fsal_status_t (*link)(struct fsal_obj_handle *obj_hdl,
struct fsal_obj_handle *destdir_hdl,
const char *name);
/**
* @brief get fs_locations
*
* This function returns the fs locations for an object.
*
* @param[in] obj_hdl Object to get fs locations for
* @param[out] fs_locations4 fs locations
*
* @return FSAL status
*/
fsal_status_t (*fs_locations)(struct fsal_obj_handle *obj_hdl,
struct fs_locations4 *fs_locs);
/**
* @brief Rename a file
*
* This function renames a file (technically it changes the name of
* one link, which may be the only link to the file.)
*
* @param[in] olddir_hdl Old parent directory
* @param[in] old_name Old name
* @param[in] newdir_hdl New parent directory
* @param[in] new_name New name
*
* @return FSAL status
*/
fsal_status_t (*rename)(struct fsal_obj_handle *obj_hdl,
struct fsal_obj_handle *olddir_hdl,
const char *old_name,
struct fsal_obj_handle *newdir_hdl,
const char *new_name);
/**
* @brief Remove a name from a directory
*
* This function removes a name from a directory and possibly deletes
* the file so named.
*
* @param[in] dir_hdl The directory from which to remove the name
* @param[in] obj_hdl The object being removed
* @param[in] name The name to remove
*
* @return FSAL status.
*/
fsal_status_t (*unlink)(struct fsal_obj_handle *dir_hdl,
struct fsal_obj_handle *obj_hdl,
const char *name);
/**@}*/
/**@{*/
/**
* I/O management
*/
/**
* @brief Open a file for read or write
*
* This function opens a file for read or write. The file should not
* already be opened when this function is called. The thread calling
* this function will have hold the Cache inode content lock
* exclusively and the FSAL may assume whatever private state it uses
* to manage open/close status is protected.
*
* @param[in] obj_hdl File to open
* @param[in] openflags Mode for open
*
* @return FSAL status.
*/
fsal_status_t (*open)(struct fsal_obj_handle *obj_hdl,
fsal_openflags_t openflags);
/**
* @brief Re-open a file that may be already opened
*
* This function reopens the file with the given open flags. You can
* atomically go from read only flag to readwrite or vice versa.
* This is used to reopen a file for readwrite, if the file is already
* opened for readonly. This will not lose any file locks that are
* already placed. May not be supported by all FSALs.
*/
fsal_status_t (*reopen)(struct fsal_obj_handle *obj_hdl,
fsal_openflags_t openflags);
/**
* @brief Return open status
*
* This function returns open flags representing the current open
* status.
*
* @param[in] obj_hdl File to interrogate
*
* @retval Flags representing current open status
*/
fsal_openflags_t (*status)(struct fsal_obj_handle *obj_hdl);
/**
* @brief Read data from a file
*
* This function reads data from the given file.
*
* @note We probably want to keep end_of_file. There may be reasons
* other than end of file while less data are returned than requested
* (FSAL_PROXY, for example, might do this depending on the will of
* the remote server.) -- ACE
*
* @param[in] obj_hdl File to read
* @param[in] offset Position from which to read
* @param[in] buffer_size Amount of data to read
* @param[out] buffer Buffer to which data are to be copied
* @param[out] read_amount Amount of data read
* @param[out] end_of_file true if the end of file has been reached
*
* @return FSAL status.
*/
fsal_status_t (*read)(struct fsal_obj_handle *obj_hdl,
uint64_t offset,
size_t buffer_size,
void *buffer,
size_t *read_amount,
bool *end_of_file); /* needed? */
/**
* @brief Read data from a file plus
*
* This function reads data from the given file.
*
* @note We probably want to keep end_of_file. There may be reasons
* other than end of file while less data are returned than requested
* (FSAL_PROXY, for example, might do this depending on the will of
* the remote server.) -- ACE
*
* @param[in] obj_hdl File to read
* @param[in] offset Position from which to read
* @param[in] buffer_size Amount of data to read
* @param[out] buffer Buffer to which data are to be copied
* @param[out] read_amount Amount of data read
* @param[out] end_of_file true if the end of file has been reached
* @param[in,out] info more information about the data
*
* @return FSAL status.
*/
fsal_status_t (*read_plus)(struct fsal_obj_handle *obj_hdl,
uint64_t offset,
size_t buffer_size,
void *buffer,
size_t *read_amount,
bool *end_of_file,
struct io_info *info);
/**
* @brief Write data to a file
*
* This function writes data to a file.
*
* @note Should buffer be const? -- ACE
*
* @param[in] obj_hdl File to be written
* @param[in] offset Position at which to write
* @param[in] buffer Data to be written
* @param[in,out] fsal_stable In, if on, the fsal is requested to write data
* to stable store. Out, the fsal reports what
* it did.
*
* @return FSAL status.
*/
fsal_status_t (*write)(struct fsal_obj_handle *obj_hdl,
uint64_t offset,
size_t buffer_size,
void *buffer,
size_t *wrote_amount,
bool *fsal_stable);
/**
* @brief Write data to a file plus
*
* This function writes data to a file.
*
* @note Should buffer be const? -- ACE
*
* @param[in] obj_hdl File to be written
* @param[in] offset Position at which to write
* @param[in] buffer Data to be written
* @param[in,out] fsal_stable In, if on, the fsal is requested to write data
* to stable store. Out, the fsal reports what
* it did.
* @param[in,out] info more information about the data
*
* @return FSAL status.
*/
fsal_status_t (*write_plus)(struct fsal_obj_handle *obj_hdl,
uint64_t offset,
size_t buffer_size,
void *buffer,
size_t *wrote_amount,
bool *fsal_stable,
struct io_info *info);
/**
* @brief Seek to data or hole
*
* This function seek to data or hole in a file.
*
* @param[in] obj_hdl File to be written
* @param[in,out] info Information about the data
*
* @return FSAL status.
*/
fsal_status_t (*seek)(struct fsal_obj_handle *obj_hdl,
struct io_info *info);
/**
* @brief IO Advise
*
* This function give hints to fs.
*
* @param[in] obj_hdl File to be written
* @param[in,out] info Information about the data
*
* @return FSAL status.
*/
fsal_status_t (*io_advise)(struct fsal_obj_handle *obj_hdl,
struct io_hints *hints);
/**
* @brief Commit written data
*
* This function flushes possibly buffered data to a file.
*
* @param[in] obj_hdl File to commit
* @param[in] offset Start of range to commit
* @param[in] len Length of range to commit
*
* @return FSAL status.
*/
fsal_status_t (*commit)(struct fsal_obj_handle *obj_hdl, /* sync */
off_t offset, size_t len);
/**
* @brief Perform a lock operation
*
* This function performs a lock operation (lock, unlock, test) on a
* file.
*
* @param[in] obj_hdl File on which to operate
* @param[in] owner Lock owner (Not yet implemented)
* @param[in] lock_op Operation to perform
* @param[in] request_lock Lock to take/release/test
* @param[out] conflicting_lock Conflicting lock
*
* @return FSAL status.
*/
fsal_status_t (*lock_op)(struct fsal_obj_handle *obj_hdl,
void *owner,
fsal_lock_op_t lock_op,
fsal_lock_param_t *request_lock,
fsal_lock_param_t *conflicting_lock);
/**
* @brief Handle share reservations
*
* This function handles acquiring and releasing Microsoft share
* reservations.
*
* @param[in] obj_hdl Handle on which to operate
* @param[in] owner Share owner
* @param[in] request_share Share reservation requested
*
* @return FSAL status.
*/
fsal_status_t (*share_op)(struct fsal_obj_handle *obj_hdl,
void *owner,
fsal_share_param_t request_share);
/**
* @brief Close a file
*
* This function closes a file. It is protected by the Cache inode
* content lock.
*
* @param[in] obj_hdl File to close
*
* @return FSAL status.
*/
fsal_status_t (*close)(struct fsal_obj_handle *obj_hdl);
/**@}*/
/**@{*/
/**
* Extended attribute management
*/
/**
* @brief List extended attributes on a file
*
* This function gets a list of attributes on a given file.
*
* @param[in] obj_hdl File to interrogate
* @param[in] cookie Attribute at which to start
* @param[out] xattrs_tab Array to which to write attributes
* @param[in] xattrs_tabsize Size of array
* @param[out] nb_returned Number of entries returned
*
* @return FSAL status.
*/
fsal_status_t (*list_ext_attrs)(struct fsal_obj_handle *obj_hdl,
unsigned int cookie,
struct fsal_xattrent *xattrs_tab,
unsigned int xattrs_tabsize,
unsigned int *nb_returned,
int *end_of_list);
/**
* @brief Get a number for an attribute name
*
* This function returns an index for a given attribute specified by
* name.
*
* @param[in] obj_hdl File to look up
* @param[in] name Name to look up
* @param[out] xattr_id Number uniquely identifying the attribute
* within the scope of the file
*
* @return FSAL status.
*/
fsal_status_t (*getextattr_id_by_name)(struct fsal_obj_handle *obj_hdl,
const char *xattr_name,
unsigned int *xattr_id);
/**
* @brief Get content of an attribute by name
*
* This function returns the value of an extended attribute as
* specified by name.
*
* @param[in] obj_hdl File to interrogate
* @param[in] xattr_name Name of attribute
* @param[out] buffer_addr Buffer to store content
* @param[in] buffer_size Buffer size
* @param[out] output_size Size of content
*
* @return FSAL status.
*/
fsal_status_t (*getextattr_value_by_name)(struct fsal_obj_handle *
obj_hdl,
const char *xattr_name,
caddr_t buffer_addr,
size_t buffer_size,
size_t *output_size);
/**
* @brief Get content of an attribute by id
*
* This function returns the value of an extended attribute as
* specified by id.
*
* @param[in] obj_hdl File to interrogate
* @param[in] xattr_id ID of attribute
* @param[out] buffer_addr Buffer to store content
* @param[in] buffer_size Buffer size
* @param[out] output_size Size of content
*
* @return FSAL status.
*/
fsal_status_t (*getextattr_value_by_id)(struct fsal_obj_handle *
obj_hdl,
unsigned int xattr_id,
caddr_t buffer_addr,
size_t buffer_size,
size_t *output_size);
/**
* @brief Set content of an attribute
*
* This function sets the value of an extended attribute.
*
* @param[in] obj_hdl File to modify
* @param[in] xattr_name Name of attribute
* @param[in] buffer_addr Content to set
* @param[in] buffer_size Content size
* @param[in] create true if attribute is to be created
*
* @return FSAL status.
*/
fsal_status_t (*setextattr_value)(struct fsal_obj_handle *obj_hdl,
const char *xattr_name,
caddr_t buffer_addr,
size_t buffer_size, int create);
/**
* @brief Set content of an attribute by id
*
* This function sets the value of an extended attribute by id.
*
* @param[in] obj_hdl File to modify
* @param[in] xattr_id ID of attribute
* @param[in] buffer_addr Content to set
* @param[in] buffer_size Content size
*
* @return FSAL status.
*/
fsal_status_t (*setextattr_value_by_id)(struct fsal_obj_handle *
obj_hdl,
unsigned int xattr_id,
caddr_t buffer_addr,
size_t buffer_size);
/**
* @brief Remove an extended attribute by id
*
* This function removes an extended attribute as specified by ID.
*
* @param[in] obj_hdl File to modify
* @param[in] xattr_id ID of attribute
*
* @return FSAL status.
*/
fsal_status_t (*remove_extattr_by_id)(struct fsal_obj_handle *obj_hdl,
unsigned int xattr_id);
/**
* @brief Remove an extended attribute by name
*
* This function removes an extended attribute as specified by name.
*
* @param[in] obj_hdl File to modify
* @param[in] xattr_name Name of attribute to remove
*
* @return FSAL status.
*/
fsal_status_t (*remove_extattr_by_name)(struct fsal_obj_handle *
obj_hdl,
const char *xattr_name);
/**@}*/
/**@{*/
/**
* Handle operations
*/
/**
* @brief Test handle type
*
* This function tests that a handle is of the specified type.
*
* @retval true if it is.
* @retval false if it isn't.
*/
bool (*handle_is)(struct fsal_obj_handle *obj_hdl,
object_file_type_t type);
/**
* @brief Write wire handle
*
* This function writes a "wire" handle or file ID to the given
* buffer.
*
* @param[in] obj_hdl The handle to digest
* @param[in] output_type The type of digest to write
* @param[in,out] fh_desc Buffer descriptor to which to write
* digest. Set fh_desc->len to final
* output length.
*
* @return FSAL status
*/
fsal_status_t (*handle_digest)(const struct fsal_obj_handle *obj_hdl,
fsal_digesttype_t output_type,
struct gsh_buffdesc *fh_desc);
/**
* @brief Get key for handle
*
* Indicate the unique part of the handle that should be used for
* hashing.
*
* @param[in] obj_hdl Handle whose key is to be got
* @param[out] fh_desc Address and length giving sub-region of handle
* to be used as key
*/
void (*handle_to_key)(struct fsal_obj_handle *obj_hdl,
struct gsh_buffdesc *fh_desc);
/**
* @brief Compare two handles
*
* This function compares two handles to see if they reference the same file
*
* @param[in] obj_hdl1 The first handle to compare
* @param[in] obj_hdl2 The second handle to compare
*
* @return True if match, false otherwise
*/
bool (*handle_cmp)(struct fsal_obj_handle *obj_hdl1,
struct fsal_obj_handle *obj_hdl2);
/**@}*/
/**@{*/
/**
* pNFS functions
*/
/**
* @brief Grant a layout segment.
*
* This function is called by nfs41_op_layoutget. It may be called
* multiple times, to satisfy a request with multiple segments. The
* FSAL may track state (what portion of the request has been or
* remains to be satisfied or any other information it wishes) in the
* bookkeeper member of res. Each segment may have FSAL-specific
* information associated with it its segid. This segid will be
* supplied to the FSAL when the segment is committed or returned.
* When the granting the last segment it intends to grant, the FSAL
* must set the last_segment flag in res.
*
* @param[in] obj_hdl The handle of the file on which the layout is
* requested.
* @param[in] req_ctx Request context
* @param[out] loc_body An XDR stream to which the FSAL must encode
* the layout specific portion of the granted
* layout segment.
* @param[in] arg Input arguments of the function
* @param[in,out] res In/out and output arguments of the function
*
* @return Valid error codes in RFC 5661, pp. 366-7.
*/
nfsstat4(*layoutget)(struct fsal_obj_handle *obj_hdl,
struct req_op_context *req_ctx,
XDR * loc_body,
const struct fsal_layoutget_arg *arg,
struct fsal_layoutget_res *res);
/**
* @brief Potentially return one layout segment
*
* This function is called once on each segment matching the IO mode
* and intersecting the range specified in a LAYOUTRETURN operation or
* for all layouts corresponding to a given stateid on last close,
* leas expiry, or a layoutreturn with a return-type of FSID or ALL.
* Whther it is called in the former or latter case is indicated by
* the synthetic flag in the arg structure, with synthetic being true
* in the case of last-close or lease expiry.
*
* If arg->dispose is true, all resources associated with the
* layout must be freed.
*
* @param[in] obj_hdl The object on which a segment is to be returned
* @param[in] req_ctx Request context
* @param[in] lrf_body In the case of a non-synthetic return, this is
* an XDR stream corresponding to the layout
* type-specific argument to LAYOUTRETURN. In
* the case of a synthetic or bulk return,
* this is a NULL pointer.
* @param[in] arg Input arguments of the function
*
* @return Valid error codes in RFC 5661, p. 367.
*/
nfsstat4(*layoutreturn)(struct fsal_obj_handle *obj_hdl,
struct req_op_context *req_ctx,
XDR * lrf_body,
const struct fsal_layoutreturn_arg *arg);
/**
* @brief Commit a segment of a layout
*
* This function is called once on every segment of a layout. The
* FSAL may avoid being called again after it has finished all tasks
* necessary for the commit by setting res->commit_done to true.
*
* The calling function does not inspect or act on the value of
* size_supplied or new_size until after the last call to
* FSAL_layoutcommit.
*
* @param[in] obj_hdl The object on which to commit
* @param[in] req_ctx Request context
* @param[in] lou_body An XDR stream containing the layout
* type-specific portion of the LAYOUTCOMMIT
* arguments.
* @param[in] arg Input arguments of the function
* @param[in,out] res In/out and output arguments of the function
*
* @return Valid error codes in RFC 5661, p. 366.
*/
nfsstat4(*layoutcommit)(struct fsal_obj_handle *obj_hdl,
struct req_op_context *req_ctx,
XDR * lou_body,
const struct fsal_layoutcommit_arg *arg,
struct fsal_layoutcommit_res *res);
/**
* @brief Get Extended Attribute
*
* This function gets an extended attribute of an object.
*
* @param[in] obj_hdl Input object to query
* @param[in] xa_name Input xattr name
* @param[out] xa_value Output xattr value
*
* @return FSAL status.
*/
fsal_status_t (*getxattrs)(struct fsal_obj_handle *obj_hdl,
xattrname4 *xa_name,
xattrvalue4 *xa_value);
/**
* @brief Set Extended Attribute
*
* This function sets an extended attribute of an object.
*
* @param[in] obj_hdl Input object to set
* @param[in] xa_type Input xattr type
* @param[in] xa_name Input xattr name to set
* @param[in] xa_value Input xattr value to set
*
* @return FSAL status.
*/
fsal_status_t (*setxattrs)(struct fsal_obj_handle *obj_hdl,
setxattr_type4 sa_type,
xattrname4 *xa_name,
xattrvalue4 *xa_value);
/**
* @brief Remove Extended Attribute
*
* This function remove an extended attribute of an object.
*
* @param[in] obj_hdl Input object to set
* @param[in] xa_name Input xattr name to remove
*
* @return FSAL status.
*/
fsal_status_t (*removexattrs)(struct fsal_obj_handle *obj_hdl,
xattrname4 *xa_name);
/**
* @brief List Extended Attributes
*
* This function list the extended attributes of an object.
*
* @param[in] obj_hdl Input object to list
* @param[in] la_maxcount Input maximum number of bytes for names
* @param[in,out] la_cookie In/out cookie
* @param[in,out] la_cookieverf In/out cookie verifier
* @param[out] lr_eof Output eof set if no more extended attributes
* @param[out] lr_names Output list of extended attribute names
* this buffer size is double the size of
* la_maxcount to allow for component4 overhead
*
* @return FSAL status.
*/
fsal_status_t (*listxattrs)(struct fsal_obj_handle *obj_hdl,
count4 la_maxcount,
nfs_cookie4 *la_cookie,
verifier4 *la_cookieverf,
bool_t *lr_eof,
xattrlist4 * lr_names);
/**@}*/
/**@{*/
/**
* Extended API functions.
*
* With these new operations, the FSAL becomes responsible for managing
* share reservations. The FSAL is also granted more control over the
* state of a "file descriptor" and has more control of what a "file
* descriptor" even is. Ultimately, it is whatever the FSAL needs in
* order to manage the share reservations and lock state.
*
* The open2 method also allows atomic create/setattr/open (just like the
* NFS v4 OPEN operation).
*
*/
/**
* @brief Open a file descriptor for read or write and possibly create
*
* This function opens a file for read or write, possibly creating it.
* If the caller is passing a state, it must hold the state_lock
* exclusive.
*
* state can be NULL which indicates a stateless open (such as via the
* NFS v3 CREATE operation), in which case the FSAL must assure protection
* of any resources. If the file is being created, such protection is
* simple since no one else will have access to the object yet, however,
* in the case of an exclusive create, the common resources may still need
* protection.
*
* If Name is NULL, obj_hdl is the file itself, otherwise obj_hdl is the
* parent directory.
*
* On an exclusive create, the upper layer may know the object handle
* already, so it MAY call with name == NULL. In this case, the caller
* expects just to check the verifier.
*
* On a call with an existing object handle for an UNCHECKED create,
* we can set the size to 0.
*
* At least the mode attribute must be set if createmode is not FSAL_NO_CREATE.
* Some FSALs may still have to pass a mode on a create call for exclusive,
* and even with FSAL_NO_CREATE, and empty set of attributes MUST be passed.
*
* If an open by name succeeds and did not result in Ganesha creating a file,
* the caller will need to do a subsequent permission check to confirm the
* open. This is because the permission attributes were not available
* beforehand.
*
* The caller is expected to invoke fsal_release_attrs to release any
* resources held by the set attributes. The FSAL layer MAY have added an
* inherited ACL.
*
* The caller will set the request_mask in attrs_out to indicate the attributes
* of interest. ATTR_ACL SHOULD NOT be requested and need not be provided. If
* not all the requested attributes can be provided, this method MUST return
* an error unless the ATTR_RDATTR_ERR bit was set in the request_mask.
*
* Since this method may instantiate a new fsal_obj_handle, it will be forced
* to fetch at least some attributes in order to even know what the object
* type is (as well as it's fileid and fsid). For this reason, the operation
* as a whole can be expected to fail if the attributes were not able to be
* fetched.
*
* The attributes will not be returned if this is an open by object as
* opposed to an open by name.
*
* @note If the file was created, @a new_obj has been ref'd
*
* @param[in] obj_hdl File to open or parent directory
* @param[in,out] state state_t to use for this operation
* @param[in] openflags Mode for open
* @param[in] createmode Mode for create
* @param[in] name Name for file if being created or opened
* @param[in] attrs_in Attributes to set on created file
* @param[in] verifier Verifier to use for exclusive create
* @param[in,out] new_obj Newly created object
* @param[in,out] attrs_out Optional attributes for newly created object
* @param[in,out] caller_perm_check The caller must do a permission check
*
* @return FSAL status.
*/
fsal_status_t (*open2)(struct fsal_obj_handle *obj_hdl,
struct state_t *state,
fsal_openflags_t openflags,
enum fsal_create_mode createmode,
const char *name,
struct attrlist *attrs_in,
fsal_verifier_t verifier,
struct fsal_obj_handle **new_obj,
struct attrlist *attrs_out,
bool *caller_perm_check);
/**
* @brief Check the exclusive create verifier for a file.
*
* @param[in] obj_hdl File to check verifier
* @param[in] verifier Verifier to use for exclusive create
*
* @retval true if verifier matches
*/
bool (*check_verifier)(struct fsal_obj_handle *obj_hdl,
fsal_verifier_t verifier);
/**
* @brief Return open status of a state.
*
* This function returns open flags representing the current open
* status for a state. The state_lock must be held.
*
* @param[in] obj_hdl File owning state
* @param[in] state File state to interrogate
*
* @retval Flags representing current open status
*/
fsal_openflags_t (*status2)(struct fsal_obj_handle *obj_hdl,
struct state_t *state);
/**
* @brief Re-open a file that may be already opened
*
* This function supports changing the access mode of a share reservation and
* thus should only be called with a share state. The state_lock must be held.
*
* This MAY be used to open a file the first time if there is no need for
* open by name or create semantics. One example would be 9P lopen.
*
* @param[in] obj_hdl File on which to operate
* @param[in] state state_t to use for this operation
* @param[in] openflags Mode for re-open
*
* @return FSAL status.
*/
fsal_status_t (*reopen2)(struct fsal_obj_handle *obj_hdl,
struct state_t *state,
fsal_openflags_t openflags);
/**
* @brief Read data from a file
*
* This function reads data from the given file. The FSAL must be able to
* perform the read whether a state is presented or not. This function also
* is expected to handle properly bypassing or not share reservations.
*
* @param[in] obj_hdl File on which to operate
* @param[in] bypass If state doesn't indicate a share reservation,
* bypass any deny read
* @param[in] state state_t to use for this operation
* @param[in] offset Position from which to read
* @param[in] buffer_size Amount of data to read
* @param[out] buffer Buffer to which data are to be copied
* @param[out] read_amount Amount of data read
* @param[out] end_of_file true if the end of file has been reached
* @param[in,out] info more information about the data
*
* @return FSAL status.
*/
fsal_status_t (*read2)(struct fsal_obj_handle *obj_hdl,
bool bypass,
struct state_t *state,
uint64_t offset,
size_t buffer_size,
void *buffer,
size_t *read_amount,
bool *end_of_file,
struct io_info *info);
/**
* @brief Write data to a file
*
* This function writes data to a file. The FSAL must be able to
* perform the write whether a state is presented or not. This function also
* is expected to handle properly bypassing or not share reservations. Even
* with bypass == true, it will enforce a mandatory (NFSv4) deny_write if
* an appropriate state is not passed).
*
* The FSAL is expected to enforce sync if necessary.
*
* @param[in] obj_hdl File on which to operate
* @param[in] bypass If state doesn't indicate a share reservation,
* bypass any non-mandatory deny write
* @param[in] state state_t to use for this operation
* @param[in] offset Position at which to write
* @param[in] buffer Data to be written
* @param[in,out] fsal_stable In, if on, the fsal is requested to write data
* to stable store. Out, the fsal reports what
* it did.
* @param[in,out] info more information about the data
*
* @return FSAL status.
*/
fsal_status_t (*write2)(struct fsal_obj_handle *obj_hdl,
bool bypass,
struct state_t *state,
uint64_t offset,
size_t buffer_size,
void *buffer,
size_t *wrote_amount,
bool *fsal_stable,
struct io_info *info);
/**
* @brief Seek to data or hole
*
* This function seek to data or hole in a file.
*
* @param[in] obj_hdl File on which to operate
* @param[in] state state_t to use for this operation
* @param[in,out] info Information about the data
*
* @return FSAL status.
*/
fsal_status_t (*seek2)(struct fsal_obj_handle *obj_hdl,
struct state_t *state,
struct io_info *info);
/**
* @brief IO Advise
*
* This function give hints to fs.
*
* @param[in] obj_hdl File on which to operate
* @param[in] state state_t to use for this operation
* @param[in,out] info Information about the data
*
* @return FSAL status.
*/
fsal_status_t (*io_advise2)(struct fsal_obj_handle *obj_hdl,
struct state_t *state,
struct io_hints *hints);
/**
* @brief Commit written data
*
* This function flushes possibly buffered data to a file. This method
* differs from commit due to the need to interact with share reservations
* and the fact that the FSAL manages the state of "file descriptors". The
* FSAL must be able to perform this operation without being passed a specific
* state.
*
* @param[in] obj_hdl File on which to operate
* @param[in] state state_t to use for this operation
* @param[in] offset Start of range to commit
* @param[in] len Length of range to commit
*
* @return FSAL status.
*/
fsal_status_t (*commit2)(struct fsal_obj_handle *obj_hdl,
off_t offset,
size_t len);
/**
* @brief Perform a lock operation
*
* This function performs a lock operation (lock, unlock, test) on a
* file. This method assumes the FSAL is able to support lock owners,
* though it need not support asynchronous blocking locks. Passing the
* lock state allows the FSAL to associate information with a specific
* lock owner for each file (which may include use of a "file descriptor".
*
* @param[in] obj_hdl File on which to operate
* @param[in] state state_t to use for this operation
* @param[in] owner Lock owner
* @param[in] lock_op Operation to perform
* @param[in] request_lock Lock to take/release/test
* @param[out] conflicting_lock Conflicting lock
*
* @return FSAL status.
*/
fsal_status_t (*lock_op2)(struct fsal_obj_handle *obj_hdl,
struct state_t *state,
void *owner,
fsal_lock_op_t lock_op,
fsal_lock_param_t *request_lock,
fsal_lock_param_t *conflicting_lock);
/**
* @brief Set attributes on an object
*
* This function sets attributes on an object. Which attributes are
* set is determined by attrib_set->mask. The FSAL must manage bypass
* or not of share reservations, and a state may be passed.
*
* The caller is expected to invoke fsal_release_attrs to release any
* resources held by the set attributes. The FSAL layer MAY have added an
* inherited ACL.
*
* @param[in] obj_hdl File on which to operate
* @param[in] bypass If state doesn't indicate a share reservation,
* bypass any non-mandatory deny write
* @param[in] state state_t to use for this operation
* @param[in] attrib_set Attributes to set
*
* @return FSAL status.
*/
fsal_status_t (*setattr2)(struct fsal_obj_handle *obj_hdl,
bool bypass,
struct state_t *state,
struct attrlist *attrib_set);
/**
* @brief Manage closing a file when a state is no longer needed.
*
* When the upper layers are ready to dispense with a state, this method is
* called to allow the FSAL to close any file descriptors or release any other
* resources associated with the state. A call to free_state should be assumed
* to follow soon.
*
* @param[in] obj_hdl File on which to operate
* @param[in] state state_t to use for this operation
*
* @return FSAL status.
*/
fsal_status_t (*close2)(struct fsal_obj_handle *obj_hdl,
struct state_t *state);
/**@}*/
};
/**
* @brief FSAL pNFS Data Server operations vector
*/
struct fsal_pnfs_ds_ops {
/**@{*/
/**
* Lifecycle management.
*/
/**
* @brief Clean up a server
*
* This function cleans up private resources associated with a
* server and deallocates it. A default is supplied.
*
* This function should not be called directly.
*
* @param[in] pds FSAL pNFS DS to release
*/
void (*release)(struct fsal_pnfs_ds *const pds);
/**
* @brief Initialize FSAL specific permissions per pNFS DS
*
* @param[in] pds FSAL pNFS DS
* @param[in] req Incoming request.
*
* @return NFSv4.1 error codes:
* NFS4_OK, NFS4ERR_ACCESS, NFS4ERR_WRONGSEC.
*/
nfsstat4(*permissions)(struct fsal_pnfs_ds *const pds,
struct svc_req *req);
/**@}*/
/**@{*/
/**
* @brief Create a FSAL data server handle from a wire handle
*
* This function creates a FSAL data server handle from a client
* supplied "wire" handle.
*
* @param[in] pds FSAL pNFS DS
* @param[in] hdl_desc Buffer from which to create the struct
* @param[out] handle FSAL DS handle
*
* @return NFSv4.1 error codes.
*/
nfsstat4(*make_ds_handle)(struct fsal_pnfs_ds *const pds,
const struct gsh_buffdesc *
const hdl_desc,
struct fsal_ds_handle **const handle,
int flags);
/**
* @brief Initialize FSAL specific values for DS handle
*
* @param[in] ops FSAL DS handle operations vector
*/
void (*fsal_dsh_ops)(struct fsal_dsh_ops *ops);
/**@}*/
};
/**
* @brief FSAL DS handle operations vector
*/
struct fsal_dsh_ops {
/**@{*/
/**
* Lifecycle management.
*/
/**
* @brief Clean up a DS handle
*
* This function cleans up private resources associated with a
* filehandle and deallocates it. Implement this method or you will
* leak. This function should not be called directly.
*
* @param[in] ds_hdl Handle to release
*/
void (*release)(struct fsal_ds_handle *const ds_hdl);
/**@}*/
/**@{*/
/**
* I/O Functions
*/
/**
* @brief Read from a data-server handle.
*
* NFSv4.1 data server handles are disjount from normal
* filehandles (in Ganesha, there is a ds_flag in the filehandle_v4_t
* structure) and do not get loaded into cache_inode or processed the
* normal way.
*
* @param[in] ds_hdl FSAL DS handle
* @param[in] req_ctx Credentials
* @param[in] stateid The stateid supplied with the READ operation,
* for validation
* @param[in] offset The offset at which to read
* @param[in] requested_length Length of read requested (and size of buffer)
* @param[out] buffer The buffer to which to store read data
* @param[out] supplied_length Length of data read
* @param[out] eof true on end of file
*
* @return An NFSv4.1 status code.
*/
nfsstat4(*read)(struct fsal_ds_handle *const ds_hdl,
struct req_op_context *const req_ctx,
const stateid4 * stateid,
const offset4 offset,
const count4 requested_length,
void *const buffer,
count4 * const supplied_length,
bool *const end_of_file);
/**
* @brief Read plus from a data-server handle.
*
* NFSv4.2 data server handles are disjount from normal
* filehandles (in Ganesha, there is a ds_flag in the filehandle_v4_t
* structure) and do not get loaded into cache_inode or processed the
* normal way.
*
* @param[in] ds_hdl FSAL DS handle
* @param[in] req_ctx Credentials
* @param[in] stateid The stateid supplied with the READ operation,
* for validation
* @param[in] offset The offset at which to read
* @param[in] requested_length Length of read requested (and size of buffer)
* @param[out] buffer The buffer to which to store read data
* @param[out] supplied_length Length of data read
* @param[out] eof true on end of file
* @param[out] info IO info
*
* @return An NFSv4.2 status code.
*/
nfsstat4(*read_plus)(struct fsal_ds_handle *const ds_hdl,
struct req_op_context *const req_ctx,
const stateid4 * stateid,
const offset4 offset,
const count4 requested_length,
void *const buffer,
const count4 supplied_length,
bool *const end_of_file,
struct io_info *info);
/**
*
* @brief Write to a data-server handle.
*
* NFSv4.1 data server filehandles are disjount from normal
* filehandles (in Ganesha, there is a ds_flag in the filehandle_v4_t
* structure) and do not get loaded into cache_inode or processed the
* normal way.
*
* @param[in] ds_hdl FSAL DS handle
* @param[in] req_ctx Credentials
* @param[in] stateid The stateid supplied with the READ operation,
* for validation
* @param[in] offset The offset at which to read
* @param[in] write_length Length of write requested (and size of buffer)
* @param[out] buffer The buffer to which to store read data
* @param[in] stability wanted Stability of write
* @param[out] written_length Length of data written
* @param[out] writeverf Write verifier
* @param[out] stability_got Stability used for write (must be as
* or more stable than request)
*
* @return An NFSv4.1 status code.
*/
nfsstat4(*write)(struct fsal_ds_handle *const ds_hdl,
struct req_op_context *const req_ctx,
const stateid4 * stateid,
const offset4 offset,
const count4 write_length,
const void *buffer,
const stable_how4 stability_wanted,
count4 * const written_length,
verifier4 * const writeverf,
stable_how4 * const stability_got);
/**
*
* @brief Write plus to a data-server handle.
*
* NFSv4.2 data server filehandles are disjount from normal
* filehandles (in Ganesha, there is a ds_flag in the filehandle_v4_t
* structure) and do not get loaded into cache_inode or processed the
* normal way.
*
* @param[in] ds_hdl FSAL DS handle
* @param[in] req_ctx Credentials
* @param[in] stateid The stateid supplied with the READ operation,
* for validation
* @param[in] offset The offset at which to read
* @param[in] write_length Length of write requested (and size of buffer)
* @param[out] buffer The buffer to which to store read data
* @param[in] stability wanted Stability of write
* @param[out] written_length Length of data written
* @param[out] writeverf Write verifier
* @param[out] stability_got Stability used for write (must be as
* or more stable than request)
* @param[in/out] info IO info
*
* @return An NFSv4.2 status code.
*/
nfsstat4(*write_plus)(struct fsal_ds_handle *const ds_hdl,
struct req_op_context *const req_ctx,
const stateid4 * stateid,
const offset4 offset,
const count4 write_length,
const void *buffer,
const stable_how4 stability_wanted,
count4 * const written_length,
verifier4 * const writeverf,
stable_how4 * const stability_got,
struct io_info *info);
/**
* @brief Commit a byte range to a DS handle.
*
* NFSv4.1 data server filehandles are disjount from normal
* filehandles (in Ganesha, there is a ds_flag in the filehandle_v4_t
* structure) and do not get loaded into cache_inode or processed the
* normal way.
*
* @param[in] ds_hdl FSAL DS handle
* @param[in] req_ctx Credentials
* @param[in] offset Start of commit window
* @param[in] count Length of commit window
* @param[out] writeverf Write verifier
*
* @return An NFSv4.1 status code.
*/
nfsstat4(*commit)(struct fsal_ds_handle *const ds_hdl,
struct req_op_context *const req_ctx,
const offset4 offset,
const count4 count,
verifier4 * const writeverf);
/**@}*/
};
/**
* @brief FSAL object definition
*
* This structure is the base FSAL instance definition, providing the
* public face to a single, loaded FSAL.
*/
struct fsal_module {
struct glist_head fsals; /*< link in list of loaded fsals */
struct glist_head exports; /*< Head of list of exports from
this FSAL */
struct glist_head handles; /*< Head of list of object handles */
struct glist_head servers; /*< Head of list of Data Servers */
char *path; /*< Path to .so file */
char *name; /*< Name set from .so and/or config */
void *dl_handle; /*< Handle to the dlopen()d shared
library. NULL if statically linked */
struct fsal_ops m_ops; /*< FSAL module methods vector */
pthread_rwlock_t lock; /*< Lock to be held when
manipulating its lists (above). */
int32_t refcount; /*< Reference count */
};
/**
* @brief Get a reference to a module
*
* @param[in] fsal_hdl FSAL on which to acquire reference.
*/
static inline void fsal_get(struct fsal_module *fsal_hdl)
{
(void) atomic_inc_int32_t(&fsal_hdl->refcount);
assert(fsal_hdl->refcount > 0);
}
/**
* @brief Relinquish a reference to the module
*
* This function relinquishes one reference to the FSAL. After the
* reference count falls to zero, the FSAL may be freed and unloaded.
*
* @param[in] fsal_hdl FSAL on which to release reference.
*/
static inline void fsal_put(struct fsal_module *fsal_hdl)
{
int32_t refcount;
refcount = atomic_dec_int32_t (&fsal_hdl->refcount);
assert(refcount >= 0);
if (refcount == 0) {
LogInfo(COMPONENT_FSAL,
"FSAL %s now unused",
fsal_hdl->name);
}
}
/**
* @brief Export object
*
* This structure is created by the @c create_export method on the
* FSAL module. It is stored as part of the export list and is used
* to manage individual exports, interrogate properties of the
* filesystem, and create individual file handle objects.
*/
struct fsal_export {
struct glist_head exports; /*< Link in list of exports from
the same FSAL. */
struct fsal_module *fsal; /*< Link back to the FSAL module */
const struct fsal_up_vector *up_ops; /*< Upcall operations */
struct export_ops exp_ops; /*< Vector of operations */
struct fsal_export *sub_export; /*< Sub export for stacking */
struct fsal_export *super_export;/*< Super export for stacking */
};
/**
* @brief Public structure for filesystem descriptions
*
* This stucture is provided along with a general interface to support those
* FSALs that map into a traditional file system model. Note that
* fsal_obj_handles do not link to an fsal_filesystem, that linkage is reserved
* for FSAL's private obj handle if appropriate.
*
*/
struct fsal_filesystem {
struct glist_head filesystems; /*< List of file systems */
struct glist_head children; /*< Child file systems */
struct glist_head siblings; /*< Entry in list of parent's child
file systems */
struct fsal_filesystem *parent; /*< Parent file system */
struct fsal_module *fsal; /*< Link back to fsal module */
void *private_data; /*< Private data for owning FSAL */
char *path; /*< Path to root of this file system */
char *device; /*< Path to block device */
char *type; /*< fs type */
unclaim_filesystem_cb unclaim; /*< Call back to unclaim this fs */
uint32_t pathlen; /*< Length of path */
uint32_t namelen; /*< Name length from statfs */
struct avltree_node avl_fsid; /*< AVL indexed by fsid */
struct avltree_node avl_dev; /*< AVL indexed by dev */
struct fsal_fsid__ fsid; /*< file system id */
fsal_dev_t dev; /*< device filesystem is on */
enum fsid_type fsid_type; /*< type of fsid present */
bool in_fsid_avl; /*< true if inserted in fsid avl */
bool in_dev_avl; /*< true if inserted in dev avl */
bool exported; /*< true if explicitly exported */
};
/**
* @brief Public structure for filesystem objects
*
* This structure is used for files of all types including directories
* and anything else that can be operated on via NFS.
*
* All functions that create a a new object handle should allocate
* memory for the complete (public and private) handle and perform any
* private initialization. They should fill the
* @c fsal_obj_handle::attributes structure. They should also call the
* @c fsal_obj_handle_init function with the public object handle,
* object handle operations vector, public export, and file type.
*
* @note Do we actually need a lock and ref count on the fsal object
* handle, since cache_inode is managing life cycle and concurrency?
* That is, do we expect fsal_obj_handle to have a reference count
* that would be separate from that managed by cache_inode_lru?
*/
struct fsal_obj_handle {
struct glist_head handles; /*< Link in list of handles under
the same FSAL. */
struct fsal_filesystem *fs; /*< Owning filesystem */
struct fsal_module *fsal; /*< Link back to fsal module */
struct fsal_obj_ops obj_ops; /*< Operations vector */
pthread_rwlock_t obj_lock; /*< Lock on handle */
/** Pointer to the cached attributes.
*
* This pointer should be set by the fsal when the handle is created.
* Its value should not be changed once initialized. The release
* of this field is also done by the FSAL.
*
* Typically the attributes are part of the FSAL's private handle,
* however, some FSALs, particularly stackable FSALs may point to
* some other field (for example, the underlying FSAL's attributes
* in the case of FSAL_NULL).
*/
/* Static attributes */
object_file_type_t type; /*< Object file type */
fsal_fsid_t fsid; /*< Filesystem on which this object is
stored */
uint64_t fileid; /*< Unique identifier for this object within
the scope of the fsid, (e.g. inode number) */
struct state_hdl *state_hdl; /*< State related to this handle */
};
/**
* @brief Public structure for pNFS Data Servers
*
* This structure is used for files of all types including directories
* and anything else that can be operated on via NFS. Having an
* independent reference count and lock here makes sense, since there
* is no caching infrastructure overlaying this system.
*
*/
enum pnfs_ds_status {
PNFS_DS_READY, /*< searchable, usable */
PNFS_DS_STALE, /*< is no longer valid */
};
struct fsal_pnfs_ds {
struct glist_head server; /*< Link in list of Data Servers under
the same FSAL. */
struct glist_head ds_handles; /*< Head of list of DS handles */
struct fsal_module *fsal; /*< Link back to fsal module */
struct fsal_pnfs_ds_ops s_ops; /*< Operations vector */
struct gsh_export *mds_export; /*< related export */
struct fsal_export *mds_fsal_export; /*< related FSAL export (avoids
MDS stacking) */
struct avltree_node ds_node; /*< Node in tree of all Data Servers. */
pthread_rwlock_t lock; /*< Lock to be held when
manipulating its list (above). */
int32_t refcount; /*< Reference count */
uint16_t id_servers; /*< Identifier */
uint8_t pnfs_ds_status; /*< current condition */
};
/**
* @brief Public structure for DS file handles
*
* This structure is used for files of all types including directories
* and anything else that can be operated on via NFS. Having an
* independent reference count and lock here makes sense, since there
* is no caching infrastructure overlaying this system.
*
*/
struct fsal_ds_handle {
struct glist_head ds_handle; /*< Link in list of DS handles under
the same pDS. */
struct fsal_pnfs_ds *pds; /*< Link back to pDS */
struct fsal_dsh_ops dsh_ops; /*< Operations vector */
int64_t refcount; /*< Reference count */
};
/**
* @brief Get a reference on a DS handle
*
* This function increments the reference count on a DS handle.
*
* @param[in] ds_hdl The handle to reference
*/
static inline void ds_handle_get_ref(struct fsal_ds_handle *const ds_hdl)
{
(void) atomic_inc_int64_t (&ds_hdl->refcount);
}
/**
* @brief Release a reference on a DS handle
*
* This function releases a reference to a DS handle. Once a caller's
* reference is released they should make no attempt to access the
* handle or even dereference a pointer to it.
*
* @param[in] ds_hdl The handle to relinquish
*/
static inline void ds_handle_put(struct fsal_ds_handle *const ds_hdl)
{
int64_t refcount = atomic_dec_int64_t (&ds_hdl->refcount);
if (refcount != 0) {
assert(refcount > 0);
return;
}
ds_hdl->dsh_ops.release(ds_hdl);
}
/**
** Resolve forward declarations
*/
#include "client_mgr.h"
#include "export_mgr.h"
#include "fsal_up.h"
#endif /* !FSAL_API */
/** @} */