From: "J. Bruce Fields" <bfields@fieldses.org>
To: David Howells <dhowells@redhat.com>
Cc: hch@infradead.org, viro@ZenIV.linux.org.uk,
linux-fsdevel@vger.kernel.org
Subject: Re: [PATCH 3/3] EXPORTFS: Update the documentation and comments and adjust the types used [try #2]
Date: Thu, 4 Dec 2008 14:32:35 -0500 [thread overview]
Message-ID: <20081204193235.GD7575@fieldses.org> (raw)
In-Reply-To: <20081203183043.2636.27982.stgit@warthog.procyon.org.uk>
On Wed, Dec 03, 2008 at 06:30:44PM +0000, David Howells wrote:
> Update the exportfs documentation and comments to fit the code, and add an
> extra FID type to be used for error indication (FILEID_ERROR).
>
> The following other code changes have been made:
>
> (*) The encode_fh() op and exportfs_encode_fh() return enum fid_type rather
> than int.
>
> (*) The exportfs_encode_fh() function has it's acceptable() function pointer
> typedef'd.
>
> (*) The fh_to_dentry() and fh_to_parent() ops and exportfs_decode_fh() take
> enum fid_type rather than int.
>
> (*) The generic_fh_to_dentry() and generic_fh_to_parent() functions now take
> enum fid_type rather than int. Their get_inode() function pointer has
> been typedef'd.
>
> (*) Returns from encode_fh() implementations of 255 are changed to
> FILEID_ERROR.
>
> (*) FAT has had its fh type #defined (FAT_FILEID).
>
> (*) FUSE has had its fh types #defined (FUSE_FILEID, FUSE_FILEID_PARENT).
>
> (*) ISOFS has had its fh types #defined (ISOFS_FILEID, ISOFS_FILEID_PARENT).
>
> (*) OCFS2 has had its fh types #defined (OCFS2_FILEID, OCFS2_FILEID_PARENT).
Could we get separate patches for these?
--b.
>
> Signed-off-by: David Howells <dhowells@redhat.com>
> ---
>
> Documentation/filesystems/Exporting | 400 +++++++++++++++++++++++------------
> fs/efs/efs.h | 5
> fs/efs/namei.c | 4
> fs/exportfs/expfs.c | 97 ++++++--
> fs/ext2/super.c | 4
> fs/ext3/super.c | 4
> fs/ext4/super.c | 4
> fs/fat/inode.c | 12 +
> fs/fuse/inode.c | 18 +-
> fs/gfs2/ops_export.c | 14 +
> fs/isofs/export.c | 19 +-
> fs/jffs2/super.c | 4
> fs/jfs/jfs_inode.h | 5
> fs/jfs/namei.c | 4
> fs/libfs.c | 10 -
> fs/ntfs/namei.c | 4
> fs/ocfs2/export.c | 21 +-
> fs/reiserfs/inode.c | 10 -
> fs/udf/namei.c | 14 +
> fs/xfs/linux-2.6/xfs_export.c | 12 +
> include/linux/exportfs.h | 117 +++++++---
> include/linux/reiserfs_fs.h | 9 -
> mm/shmem.c | 6 -
> 23 files changed, 512 insertions(+), 285 deletions(-)
>
>
> diff --git a/Documentation/filesystems/Exporting b/Documentation/filesystems/Exporting
> index 87019d2..5d9d769 100644
> --- a/Documentation/filesystems/Exporting
> +++ b/Documentation/filesystems/Exporting
> @@ -1,147 +1,273 @@
> + =============================
> + MAKING FILESYSTEMS EXPORTABLE
> + =============================
>
> -Making Filesystems Exportable
> -=============================
> -
> -Overview
> ---------
> -
> -All filesystem operations require a dentry (or two) as a starting
> -point. Local applications have a reference-counted hold on suitable
> -dentries via open file descriptors or cwd/root. However remote
> -applications that access a filesystem via a remote filesystem protocol
> -such as NFS may not be able to hold such a reference, and so need a
> -different way to refer to a particular dentry. As the alternative
> -form of reference needs to be stable across renames, truncates, and
> -server-reboot (among other things, though these tend to be the most
> -problematic), there is no simple answer like 'filename'.
> -
> -The mechanism discussed here allows each filesystem implementation to
> -specify how to generate an opaque (outside of the filesystem) byte
> -string for any dentry, and how to find an appropriate dentry for any
> -given opaque byte string.
> -This byte string will be called a "filehandle fragment" as it
> -corresponds to part of an NFS filehandle.
> -
> -A filesystem which supports the mapping between filehandle fragments
> -and dentries will be termed "exportable".
> -
> -
> -
> -Dcache Issues
> --------------
> -
> -The dcache normally contains a proper prefix of any given filesystem
> -tree. This means that if any filesystem object is in the dcache, then
> -all of the ancestors of that filesystem object are also in the dcache.
> -As normal access is by filename this prefix is created naturally and
> -maintained easily (by each object maintaining a reference count on
> -its parent).
> -
> -However when objects are included into the dcache by interpreting a
> -filehandle fragment, there is no automatic creation of a path prefix
> -for the object. This leads to two related but distinct features of
> -the dcache that are not needed for normal filesystem access.
> -
> -1/ The dcache must sometimes contain objects that are not part of the
> - proper prefix. i.e that are not connected to the root.
> -2/ The dcache must be prepared for a newly found (via ->lookup) directory
> - to already have a (non-connected) dentry, and must be able to move
> - that dentry into place (based on the parent and name in the
> - ->lookup). This is particularly needed for directories as
> - it is a dcache invariant that directories only have one dentry.
> -
> -To implement these features, the dcache has:
> -
> -a/ A dentry flag DCACHE_DISCONNECTED which is set on
> - any dentry that might not be part of the proper prefix.
> - This is set when anonymous dentries are created, and cleared when a
> - dentry is noticed to be a child of a dentry which is in the proper
> - prefix.
> -
> -b/ A per-superblock list "s_anon" of dentries which are the roots of
> - subtrees that are not in the proper prefix. These dentries, as
> - well as the proper prefix, need to be released at unmount time. As
> - these dentries will not be hashed, they are linked together on the
> - d_hash list_head.
> -
> -c/ Helper routines to allocate anonymous dentries, and to help attach
> - loose directory dentries at lookup time. They are:
> - d_alloc_anon(inode) will return a dentry for the given inode.
> - If the inode already has a dentry, one of those is returned.
> - If it doesn't, a new anonymous (IS_ROOT and
> - DCACHE_DISCONNECTED) dentry is allocated and attached.
> - In the case of a directory, care is taken that only one dentry
> - can ever be attached.
> - d_splice_alias(inode, dentry) will make sure that there is a
> - dentry with the same name and parent as the given dentry, and
> - which refers to the given inode.
> - If the inode is a directory and already has a dentry, then that
> - dentry is d_moved over the given dentry.
> - If the passed dentry gets attached, care is taken that this is
> - mutually exclusive to a d_alloc_anon operation.
> - If the passed dentry is used, NULL is returned, else the used
> - dentry is returned. This corresponds to the calling pattern of
> - ->lookup.
> -
> -
> -Filesystem Issues
> ------------------
> +Contents:
> +
> + (*) Overview.
> +
> + (*) Dealing with the directory entry cache.
> +
> + (*) Making a filesystem exportable.
> +
> + (*) Filehandle fragment format.
> +
> + (*) Filehandle export operations.
> +
> +
> +========
> +OVERVIEW
> +========
> +
> +All filesystem operations require a dentry (or two) as a starting point. Local
> +applications have a reference-counted hold on suitable dentries via open file
> +descriptors, the current working directory and the current root directory.
> +Remote applications that access a filesystem via a remote filesystem protocol
> +such as NFS, however, may not be able to hold such a reference, and so need a
> +different way to refer to a particular dentry. As the alternative form of
> +reference needs to be persistent across renames, truncates, and server reboots
> +(among other events, though these tend to be the most problematic), there is no
> +simple answer like 'filename'.
> +
> +The mechanism discussed here allows each filesystem implementation to specify
> +how to generate an opaque (outside of the filesystem) byte string for any
> +dentry, and how to find an appropriate dentry for any given opaque byte string.
> +
> +This byte string will be called a "filehandle fragment" as it corresponds to
> +part of an NFS filehandle.
> +
> +A filesystem which supports the mapping between filehandle fragments and
> +dentries will be termed "exportable".
> +
> +
> +======================================
> +DEALING WITH THE DIRECTORY ENTRY CACHE
> +======================================
> +
> +Each superblock has a tree of directory entries (dentries) that is rooted at
> +its s_root pointer. For most filesystems, every dentry it currently has cached
> +in RAM is connected to this tree, meaning that all the ancestors of most files
> +are fully represented in the directory entry cache (dcache).
> +
> +As the normal method of accessing files is by filename, the superblock root
> +tree builds up in a natural manner, and is maintained simply by each object
> +having a reference count on its parent. The pathwalk algorithm works by
> +walking from the root and out along the branches to the desired object.
> +
> +However, when an object is brought into the dcache by interpreting a filehandle
> +fragment, the entries for the directories that represent that object's ancestry
> +are not automatically all brought into the cache as well. This leads to two
> +related but distinct issues in the dcache that are not ordinarily seen:
> +
> + (1) Sometimes the dcache for a superblock must contain objects that are not
> + connected to that superblock's root tree.
> +
> + (2) The dcache must be able to handle a lookup() operation that results in a
> + dentry that already exists. In such a case, the already extant dentry
> + must be used instead of the candidate upon which the lookup was performed.
> +
> + Furthermore, the lookup procedure must be able to handle unconnected
> + dentries so found by installing them in the dentry tree under the parent
> + specified directory.
> +
> + This is particularly necessary for directories as it is a requirement of
> + the dcache that directories are represented by a single dentry and don't
> + have aliases.
> +
> +To manage the above, the dcache has the following features:
> +
> + (A) A dentry flag DCACHE_DISCONNECTED which is set on any dentry that might
> + not be connected to the superblock root. This is set when anonymous
> + dentries are created, and cleared when a dentry is noticed to be a child
> + of a dentry which is in the proper prefix.
> +
> + (B) A per-superblock list of dentries (s_anon) which are the roots of subtrees
> + that are not connected to the superblock root. These dentries, as well as
> + the superblock's rooted tree, need to be released at unmount time.
> +
> + Note that as these dentries are unhashed, the s_anon list is linked
> + together using the d_hash list_head in the dentry struct.
> +
> + (C) Helper routines to allocate anonymous dentries, and to help attach loose
> + directory dentries at lookup time. They are:
> +
> + (*) Find or allocate a dentry for a given inode.
> +
> + struct dentry *d_obtain_alias(struct inode *inode);
> +
> + This will return a dentry for the given inode. If the inode already
> + has a dentry, one of those is returned. If it doesn't, a new
> + anonymous (IS_ROOT() and DCACHE_DISCONNECTED) dentry is allocated and
> + attached. In the case of a directory, care is taken that only one
> + dentry can ever be attached.
> +
> + (*) Splice a disconnected dentry into the tree if one exists.
> +
> + struct dentry *d_splice_alias(struct inode *inode,
> + struct dentry *dentry);
> +
> + This will make sure that there is a dentry with the same name and
> + parent as the given dentry, and which refers to the given inode.
> +
> + If the inode is a directory and already has a dentry, then that dentry
> + is d_move()'d over the given dentry. If the passed dentry gets
> + attached, care is taken that this is mutually exclusive to a
> + d_obtain_alias() operation. If the passed dentry is used, NULL is
> + returned, else the used dentry is returned. This corresponds to the
> + calling pattern of the lookup procedure.
> +
> +
> +==============================
> +MAKING A FILESYSTEM EXPORTABLE
> +==============================
>
> For a filesystem to be exportable it must:
> -
> - 1/ provide the filehandle fragment routines described below.
> - 2/ make sure that d_splice_alias is used rather than d_add
> - when ->lookup finds an inode for a given parent and name.
> - Typically the ->lookup routine will end with a:
>
> + (1) Provide the filehandle export operations described below.
> +
> + (2) Make sure that d_splice_alias() is used rather than d_add() when its
> + lookup() operation finds an inode for a given parent and name. Typically
> + the lookup() routine will end with a:
> +
> + {
> + ...
> return d_splice_alias(inode, dentry);
> }
>
>
> +==========================
> +FILEHANDLE FRAGMENT FORMAT
> +==========================
> +
> +A filehandle fragment consists of an array of 1 or more 32-bit words. The
> +contents and the layout of the data in the array are entirely at the whim of
> +the filesystem that generated it.
> +
> +The filehandle fragment produced also has a 'type' associated with it. This
> +is a number between 0 and 254. 0 is a special reserved value (FILEID_ROOT)
> +that encode_fh() may not produce. The remaining values in that range can be
> +chosen at will, though there are possible symbols in the fid_type enum that can
> +be used if desired. Beware, though, these may be decoded by protocol decoding
> +programs, such as wireshark, so using a predefined type may confuse people if
> +the corresponding format is not also adhered to (see the fid struct).
>
> - A file system implementation declares that instances of the filesystem
> -are exportable by setting the s_export_op field in the struct
> -super_block. This field must point to a "struct export_operations"
> -struct which has the following members:
> -
> - encode_fh (optional)
> - Takes a dentry and creates a filehandle fragment which can later be used
> - to find or create a dentry for the same object. The default
> - implementation creates a filehandle fragment that encodes a 32bit inode
> - and generation number for the inode encoded, and if necessary the
> - same information for the parent.
> -
> - fh_to_dentry (mandatory)
> - Given a filehandle fragment, this should find the implied object and
> - create a dentry for it (possibly with d_alloc_anon).
> -
> - fh_to_parent (optional but strongly recommended)
> - Given a filehandle fragment, this should find the parent of the
> - implied object and create a dentry for it (possibly with d_alloc_anon).
> - May fail if the filehandle fragment is too small.
> -
> - get_parent (optional but strongly recommended)
> - When given a dentry for a directory, this should return a dentry for
> - the parent. Quite possibly the parent dentry will have been allocated
> - by d_alloc_anon. The default get_parent function just returns an error
> - so any filehandle lookup that requires finding a parent will fail.
> - ->lookup("..") is *not* used as a default as it can leave ".." entries
> - in the dcache which are too messy to work with.
> -
> - get_name (optional)
> - When given a parent dentry and a child dentry, this should find a name
> - in the directory identified by the parent dentry, which leads to the
> - object identified by the child dentry. If no get_name function is
> - supplied, a default implementation is provided which uses vfs_readdir
> - to find potential names, and matches inode numbers to find the correct
> - match.
> -
> -
> -A filehandle fragment consists of an array of 1 or more 4byte words,
> -together with a one byte "type".
> -The decode_fh routine should not depend on the stated size that is
> -passed to it. This size may be larger than the original filehandle
> -generated by encode_fh, in which case it will have been padded with
> -nuls. Rather, the encode_fh routine should choose a "type" which
> -indicates the decode_fh how much of the filehandle is valid, and how
> +The fh_to_dentry() and fh_to_parent() routines should not depend on the stated
> +size that is passed to them. This size may be larger than the original
> +filehandle generated by encode_fh(), in which case it will have been padded
> +with NULs. Rather, the encode_fh() routine should choose a "type" which
> +indicates the fh_to_*() operations how much of the filehandle is valid, and how
> it should be interpreted.
> +
> +
> +============================
> +FILEHANDLE EXPORT OPERATIONS
> +============================
> +
> +A filesystem implementation declares that instances of the filesystem are
> +exportable by setting the s_export_op field in the super_block struct. This
> +field must point to an export_operations struct which has the following members
> +filled in:
> +
> + (*) enum fid_type (*encode_fh)(struct dentry *de, __u32 *fh, int *max_len,
> + int connectable);
> +
> + This operation is used to generate a filehandle fragment that can later be
> + used to find or create a dentry for the same filesystem object. It is
> + optional and there's a default encoder.
> +
> + The fragment is written into the supplied buffer - fh - which can hold up
> + to *max_len lots of 4-byte words. The fragment generated should represent
> + the given dentry, and if connectable is set, the parent of the given
> + dentry too.
> +
> + If successful, this operation should return a value that represents to the
> + decoder operations the format of the opaque fragment produced and it
> + should set *max_len to indicate the amount of data it stored in the buffer
> + in units of 32-bit words.
> +
> + The caller is required to save the type value for presentation to the
> + decoder operations. The type value is arbitrary, but must be between 1
> + and 254. There are some predefined types in the fid_type enum that can be
> + selected, but use of these is not mandatory.
> +
> + Upon failure, a value of FILEID_ERROR should be returned.
> +
> + The default encoder uses the i_ino and i_generation numbers from the
> + inode, both masked down to 32-bits. It also adds both values from the
> + parent inode if connectable.
> +
> + (*) struct dentry *(*fh_to_dentry)(struct super_block *sb, struct fid *fid,
> + int fh_len, enum fid_type fh_type);
> +
> + This operation is used to look up a file, given the filehandle fragment
> + that was generated by encode_fh(). The file, if it exists, will be one of
> + the set available through the specified superblock. This operation is
> + mandatory.
> +
> + The filehandle fragment is in the buffer specified by fid and is of up to
> + fh_len 32-bit words and is of type fh_type as indicated by encode_fh().
> + Note that there may be more data than expected in the buffer as the data
> + may have been padded out by the caller. fh_type must be used to deal with
> + this.
> +
> + If successful, this operation should return a pointer to a dcache entry
> + representing one of the aliases to the file. This may be used by the
> + caller to query other aliases of the same file to find one it prefers.
> +
> + Note that this operation is not required to produce an dentry that is
> + connected to the root of the superblock. It is permitted to produce an
> + anonymous dentry, as might happen if encode_fh() was given connectable as
> + false.
> +
> + On failure, a negative error code should be produced to indicate the
> + reason. A NULL pointer must not be returned.
> +
> + (*) struct dentry *(*fh_to_parent)(struct super_block *sb, struct fid *fid,
> + int fh_len, enum fid_type fh_type);
> +
> + This is very similar to fh_to_dentry(), the difference being that it
> + attempts to retrieve the parent of the file to which the filehandle
> + fragment corresponds, rather than the file itself. This operation is
> + optional, but is strongly recommended.
> +
> + This may fail if the filehandle does not contain information on the
> + original file's parentage. It also need not produce a fully connected
> + dentry.
> +
> + (*) struct dentry *(*get_parent)(struct dentry *child);
> +
> + This operation should return a dentry to represent the parent directory of
> + the specified dentry (which should itself be a directory). This operation
> + is optional, but strongly recommended.
> +
> + An anonymous, unconnected dentry can be returned as the parent if so
> + desired. This may be allocated with d_obtain_alias() or suchlike.
> +
> + On success, the parent dentry should be returned. On failure, a negative
> + error code should be returned.
> +
> + The default operation just returns an error, thus making any filehandle
> + lookup that requires finding the parent fail. The default operation does
> + not try to use 'lookup("..")' as that could leave ".." entries in the
> + dcache.
> +
> + (*) int (*get_name)(struct dentry *parent, char *name, struct dentry *child);
> +
> + This operation is provided to determine the name of the directory entry in
> + the parent directory that points to the child object. This operation is
> + optional.
> +
> + On success, the NUL-terminated name of the directory entry should be
> + written into the name buffer, and zero should be returned. The caller
> + must guarantee that the buffer is at least NAME_MAX + 1 in size.
> +
> + On failure, a negative error code should be returned.
> +
> + The default operation is available that uses vfs_readdir() to find
> + potential names and match inode numbers to select the correct entry.
> +
> +This interface can be included in the code by:
> +
> + #include <linux/exportfs.h>
> +
> +and making the user dependent on CONFIG_EXPORTFS.
> diff --git a/fs/efs/efs.h b/fs/efs/efs.h
> index d8305b5..db5e1c2 100644
> --- a/fs/efs/efs.h
> +++ b/fs/efs/efs.h
> @@ -8,6 +8,7 @@
> #define _EFS_EFS_H_
>
> #include <linux/fs.h>
> +#include <linux/exportfs.h>
> #include <asm/uaccess.h>
>
> #define EFS_VERSION "1.0a"
> @@ -131,9 +132,9 @@ extern int efs_get_block(struct inode *, sector_t, struct buffer_head *, int);
>
> extern struct dentry *efs_lookup(struct inode *, struct dentry *, struct nameidata *);
> extern struct dentry *efs_fh_to_dentry(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type);
> + int fh_len, enum fid_type fh_type);
> extern struct dentry *efs_fh_to_parent(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type);
> + int fh_len, enum fid_type fh_type);
> extern struct dentry *efs_get_parent(struct dentry *);
> extern int efs_bmap(struct inode *, int);
>
> diff --git a/fs/efs/namei.c b/fs/efs/namei.c
> index c3fb5f9..6b9c118 100644
> --- a/fs/efs/namei.c
> +++ b/fs/efs/namei.c
> @@ -97,14 +97,14 @@ static struct inode *efs_nfs_get_inode(struct super_block *sb, u64 ino,
> }
>
> struct dentry *efs_fh_to_dentry(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type)
> + int fh_len, enum fid_type fh_type)
> {
> return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
> efs_nfs_get_inode);
> }
>
> struct dentry *efs_fh_to_parent(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type)
> + int fh_len, enum fid_type fh_type)
> {
> return generic_fh_to_parent(sb, fid, fh_len, fh_type,
> efs_nfs_get_inode);
> diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
> index ec1fb91..46039b4 100644
> --- a/fs/exportfs/expfs.c
> +++ b/fs/exportfs/expfs.c
> @@ -35,12 +35,12 @@ static int exportfs_get_name(struct vfsmount *mnt, struct dentry *dir,
> }
>
> /*
> - * Check if the dentry or any of it's aliases is acceptable.
> + * Check if the dentry or any of it's aliases are acceptable.
> */
> static struct dentry *
> find_acceptable_alias(struct dentry *result,
> - int (*acceptable)(void *context, struct dentry *dentry),
> - void *context)
> + exportfs_acceptable_t acceptable,
> + void *context)
> {
> struct dentry *dentry, *toput = NULL;
>
> @@ -303,25 +303,25 @@ out:
>
> /**
> * export_encode_fh - default export_operations->encode_fh function
> - * @dentry: the dentry to encode
> - * @fh: where to store the file handle fragment
> - * @max_len: maximum length to store there
> - * @connectable: whether to store parent information
> + * @dentry: The dentry to encode
> + * @fid: Where to store the file handle fragment
> + * @max_len: Maximum length to store there in 32-bit words
> + * @connectable: Whether to store parent information
> *
> - * This default encode_fh function assumes that the 32 inode number
> - * is suitable for locating an inode, and that the generation number
> - * can be used to check that it is still valid. It places them in the
> - * filehandle fragment where export_decode_fh expects to find them.
> + * This default encode_fh function assumes that the 32 inode number is suitable
> + * for locating an inode, and that the generation number can be used to check
> + * that it is still valid. It places them in the filehandle fragment where
> + * export_decode_fh expects to find them.
> */
> -static int export_encode_fh(struct dentry *dentry, struct fid *fid,
> - int *max_len, int connectable)
> +static enum fid_type export_encode_fh(struct dentry *dentry, struct fid *fid,
> + int *max_len, int connectable)
> {
> struct inode * inode = dentry->d_inode;
> int len = *max_len;
> - int type = FILEID_INO32_GEN;
> -
> + enum fid_type type = FILEID_INO32_GEN;
> +
> if (len < 2 || (connectable && len < 4))
> - return 255;
> + return FILEID_ERROR;
>
> len = 2;
> fid->i32.ino = inode->i_ino;
> @@ -341,24 +341,71 @@ static int export_encode_fh(struct dentry *dentry, struct fid *fid,
> return type;
> }
>
> -int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, int *max_len,
> - int connectable)
> +/**
> + * exportfs_encode_fh - Encode a dentry to a partial persistent file handle
> + * @dentry: The dentry to encode
> + * @fid: Where to store the file handle fragment
> + * @max_len: Maximum length to store there in 32-bit words
> + * @connectable: Whether to store parent information
> + *
> + * This function is used to get a partial persistent file handle to represent a
> + * file object as referred to by the given dentry. The caller may also request
> + * that parentage information be noted in the file handle produced.
> + *
> + * The fid pointer should point to a buffer of *max_len size, where the maximum
> + * length is given in 32-bit words, _not_ bytes. The contents of the returned
> + * file handle may or may not reflect the layout of the fid structure. That is
> + * totally up to the filesystem being queried.
> + *
> + * On return, the file handle type will be returned, or FILEID_ERROR if the
> + * filesystem was unable to represent the file. The caller is responsible for
> + * saving the type so that it can be passed to exportfs_decode_fh().
> + *
> + * If successful, *max_len will have been updated to specify the amount of
> + * buffer actually used.
> + */
> +enum fid_type exportfs_encode_fh(struct dentry *dentry, struct fid *fid,
> + int *max_len, int connectable)
> {
> const struct export_operations *nop = dentry->d_sb->s_export_op;
> - int error;
>
> if (nop->encode_fh)
> - error = nop->encode_fh(dentry, fid->raw, max_len, connectable);
> + return nop->encode_fh(dentry, fid->raw, max_len, connectable);
> else
> - error = export_encode_fh(dentry, fid, max_len, connectable);
> -
> - return error;
> + return export_encode_fh(dentry, fid, max_len, connectable);
> }
> EXPORT_SYMBOL_GPL(exportfs_encode_fh);
>
> +/**
> + * exportfs_decode_fh - Decode a partial persistent file handle to a dentry
> + * @mnt: The mountpoint with which the dentry should be associated
> + * @fid: The partial file handle
> + * @fh_len: The length of the partial file handle
> + * @fileid_type: The type of partial file handle
> + * @acceptable: A filter routine to pick amongst the aliases for an inode
> + * @context: Context information for the acceptability filter
> + *
> + * This function function is used to turn a partial persistent file handle back
> + * into the dentry it represents. The caller must indicate the set of dentries
> + * from which the target is to be selected by the VFS mountpoint supplied.
> + *
> + * The partial file handle is in the buffer pointed to by the fid pointer, and
> + * is fh_len 32-bit words in length. The fileid_type as returned by the encode
> + * routine must also be presented by the caller.
> + *
> + * If a suitable inode is found, its list of aliases will be passed to the
> + * acceptability function to select a suitable one. The context information
> + * supplied will be passed to the acceptability filter to aid in selection.
> + *
> + * If successful, a pointer to a suitable dentry will be returned. Note that
> + * dentry returned may not be connected to any of the superblock's roots.
> + *
> + * If unsuccessful, a negative error code will be returned.
> + */
> struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
> - int fh_len, int fileid_type,
> - int (*acceptable)(void *, struct dentry *), void *context)
> + int fh_len, enum fid_type fileid_type,
> + exportfs_acceptable_t acceptable,
> + void *context)
> {
> const struct export_operations *nop = mnt->mnt_sb->s_export_op;
> struct dentry *result, *alias;
> diff --git a/fs/ext2/super.c b/fs/ext2/super.c
> index 647cd88..a3ef820 100644
> --- a/fs/ext2/super.c
> +++ b/fs/ext2/super.c
> @@ -340,14 +340,14 @@ static struct inode *ext2_nfs_get_inode(struct super_block *sb,
> }
>
> static struct dentry *ext2_fh_to_dentry(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type)
> + int fh_len, enum fid_type fh_type)
> {
> return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
> ext2_nfs_get_inode);
> }
>
> static struct dentry *ext2_fh_to_parent(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type)
> + int fh_len, enum fid_type fh_type)
> {
> return generic_fh_to_parent(sb, fid, fh_len, fh_type,
> ext2_nfs_get_inode);
> diff --git a/fs/ext3/super.c b/fs/ext3/super.c
> index f6c94f2..b549bbd 100644
> --- a/fs/ext3/super.c
> +++ b/fs/ext3/super.c
> @@ -669,14 +669,14 @@ static struct inode *ext3_nfs_get_inode(struct super_block *sb,
> }
>
> static struct dentry *ext3_fh_to_dentry(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type)
> + int fh_len, enum fid_type fh_type)
> {
> return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
> ext3_nfs_get_inode);
> }
>
> static struct dentry *ext3_fh_to_parent(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type)
> + int fh_len, enum fid_type fh_type)
> {
> return generic_fh_to_parent(sb, fid, fh_len, fh_type,
> ext3_nfs_get_inode);
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index e4a241c..30e142b 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -759,14 +759,14 @@ static struct inode *ext4_nfs_get_inode(struct super_block *sb,
> }
>
> static struct dentry *ext4_fh_to_dentry(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type)
> + int fh_len, enum fid_type fh_type)
> {
> return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
> ext4_nfs_get_inode);
> }
>
> static struct dentry *ext4_fh_to_parent(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type)
> + int fh_len, enum fid_type fh_type)
> {
> return generic_fh_to_parent(sb, fid, fh_len, fh_type,
> ext4_nfs_get_inode);
> diff --git a/fs/fat/inode.c b/fs/fat/inode.c
> index cac84f2..b0bb1f4 100644
> --- a/fs/fat/inode.c
> +++ b/fs/fat/inode.c
> @@ -649,14 +649,16 @@ static const struct super_operations fat_sops = {
> * of i_logstart is used to store the directory entry offset.
> */
>
> +#define FAT_FILEID 3
> +
> static struct dentry *fat_fh_to_dentry(struct super_block *sb,
> - struct fid *fid, int fh_len, int fh_type)
> + struct fid *fid, int fh_len, enum fid_type fh_type)
> {
> struct inode *inode = NULL;
> struct dentry *result;
> u32 *fh = fid->raw;
>
> - if (fh_len < 5 || fh_type != 3)
> + if (fh_len < 5 || fh_type != FAT_FILEID)
> return ERR_PTR(-ESTALE);
>
> inode = ilookup(sb, fh[0]);
> @@ -704,7 +706,7 @@ static struct dentry *fat_fh_to_dentry(struct super_block *sb,
> return result;
> }
>
> -static int
> +static enum fid_type
> fat_encode_fh(struct dentry *de, __u32 *fh, int *lenp, int connectable)
> {
> int len = *lenp;
> @@ -712,7 +714,7 @@ fat_encode_fh(struct dentry *de, __u32 *fh, int *lenp, int connectable)
> u32 ipos_h, ipos_m, ipos_l;
>
> if (len < 5)
> - return 255; /* no room */
> + return FILEID_ERROR; /* no room */
>
> ipos_h = MSDOS_I(inode)->i_pos >> 8;
> ipos_m = (MSDOS_I(inode)->i_pos & 0xf0) << 24;
> @@ -725,7 +727,7 @@ fat_encode_fh(struct dentry *de, __u32 *fh, int *lenp, int connectable)
> spin_lock(&de->d_lock);
> fh[4] = ipos_l | MSDOS_I(de->d_parent->d_inode)->i_logstart;
> spin_unlock(&de->d_lock);
> - return 3;
> + return FAT_FILEID;
> }
>
> static struct dentry *fat_get_parent(struct dentry *child)
> diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
> index 0eb8990..3e1da5c 100644
> --- a/fs/fuse/inode.c
> +++ b/fs/fuse/inode.c
> @@ -610,8 +610,11 @@ static struct dentry *fuse_get_dentry(struct super_block *sb,
> return ERR_PTR(err);
> }
>
> -static int fuse_encode_fh(struct dentry *dentry, u32 *fh, int *max_len,
> - int connectable)
> +#define FUSE_FILEID 0x81
> +#define FUSE_FILEID_PARENT 0x82
> +
> +static enum fid_type fuse_encode_fh(struct dentry *dentry, u32 *fh,
> + int *max_len, int connectable)
> {
> struct inode *inode = dentry->d_inode;
> bool encode_parent = connectable && !S_ISDIR(inode->i_mode);
> @@ -620,7 +623,7 @@ static int fuse_encode_fh(struct dentry *dentry, u32 *fh, int *max_len,
> u32 generation;
>
> if (*max_len < len)
> - return 255;
> + return FILEID_ERROR;
>
> nodeid = get_fuse_inode(inode)->nodeid;
> generation = inode->i_generation;
> @@ -644,15 +647,16 @@ static int fuse_encode_fh(struct dentry *dentry, u32 *fh, int *max_len,
> }
>
> *max_len = len;
> - return encode_parent ? 0x82 : 0x81;
> + return encode_parent ? FUSE_FILEID_PARENT : FUSE_FILEID;
> }
>
> static struct dentry *fuse_fh_to_dentry(struct super_block *sb,
> - struct fid *fid, int fh_len, int fh_type)
> + struct fid *fid, int fh_len, enum fid_type fh_type)
> {
> struct fuse_inode_handle handle;
>
> - if ((fh_type != 0x81 && fh_type != 0x82) || fh_len < 3)
> + if ((fh_type != FUSE_FILEID && fh_type != FUSE_FILEID_PARENT) ||
> + fh_len < 3)
> return ERR_PTR(-ESTALE);
>
> handle.nodeid = (u64) fid->raw[0] << 32;
> @@ -662,7 +666,7 @@ static struct dentry *fuse_fh_to_dentry(struct super_block *sb,
> }
>
> static struct dentry *fuse_fh_to_parent(struct super_block *sb,
> - struct fid *fid, int fh_len, int fh_type)
> + struct fid *fid, int fh_len, enum fid_type fh_type)
> {
> struct fuse_inode_handle parent;
>
> diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c
> index 2864873..8d0d6cf 100644
> --- a/fs/gfs2/ops_export.c
> +++ b/fs/gfs2/ops_export.c
> @@ -31,8 +31,8 @@
> #define GFS2_LARGE_FH_SIZE 8
> #define GFS2_OLD_FH_SIZE 10
>
> -static int gfs2_encode_fh(struct dentry *dentry, __u32 *p, int *len,
> - int connectable)
> +static enum fid_type gfs2_encode_fh(struct dentry *dentry, __u32 *p,
> + int *len, int connectable)
> {
> __be32 *fh = (__force __be32 *)p;
> struct inode *inode = dentry->d_inode;
> @@ -41,7 +41,7 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *p, int *len,
>
> if (*len < GFS2_SMALL_FH_SIZE ||
> (connectable && *len < GFS2_LARGE_FH_SIZE))
> - return 255;
> + return FILEID_ERROR;
>
> fh[0] = cpu_to_be32(ip->i_no_formal_ino >> 32);
> fh[1] = cpu_to_be32(ip->i_no_formal_ino & 0xFFFFFFFF);
> @@ -50,7 +50,7 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *p, int *len,
> *len = GFS2_SMALL_FH_SIZE;
>
> if (!connectable || inode == sb->s_root->d_inode)
> - return *len;
> + return GFS2_SMALL_FH_SIZE;
>
> spin_lock(&dentry->d_lock);
> inode = dentry->d_parent->d_inode;
> @@ -66,7 +66,7 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *p, int *len,
>
> iput(inode);
>
> - return *len;
> + return GFS2_LARGE_FH_SIZE;
> }
>
> struct get_name_filldir {
> @@ -239,7 +239,7 @@ fail:
> }
>
> static struct dentry *gfs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type)
> + int fh_len, enum fid_type fh_type)
> {
> struct gfs2_inum_host this;
> __be32 *fh = (__force __be32 *)fid->raw;
> @@ -259,7 +259,7 @@ static struct dentry *gfs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
> }
>
> static struct dentry *gfs2_fh_to_parent(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type)
> + int fh_len, enum fid_type fh_type)
> {
> struct gfs2_inum_host parent;
> __be32 *fh = (__force __be32 *)fid->raw;
> diff --git a/fs/isofs/export.c b/fs/isofs/export.c
> index 1b4ee23..3d6cfd8 100644
> --- a/fs/isofs/export.c
> +++ b/fs/isofs/export.c
> @@ -106,7 +106,10 @@ static struct dentry *isofs_export_get_parent(struct dentry *child)
> return rv;
> }
>
> -static int
> +#define ISOFS_FILEID 1
> +#define ISOFS_FILEID_PARENT 2
> +
> +static enum fid_type
> isofs_export_encode_fh(struct dentry *dentry,
> __u32 *fh32,
> int *max_len,
> @@ -115,7 +118,7 @@ isofs_export_encode_fh(struct dentry *dentry,
> struct inode * inode = dentry->d_inode;
> struct iso_inode_info * ei = ISOFS_I(inode);
> int len = *max_len;
> - int type = 1;
> + enum fid_type type = ISOFS_FILEID;
> __u16 *fh16 = (__u16*)fh32;
>
> /*
> @@ -126,7 +129,7 @@ isofs_export_encode_fh(struct dentry *dentry,
> */
>
> if (len < 3 || (connectable && len < 5))
> - return 255;
> + return FILEID_ERROR;
>
> len = 3;
> fh32[0] = ei->i_iget5_block;
> @@ -143,7 +146,7 @@ isofs_export_encode_fh(struct dentry *dentry,
> fh32[4] = parent->i_generation;
> spin_unlock(&dentry->d_lock);
> len = 5;
> - type = 2;
> + type = ISOFS_FILEID_PARENT;
> }
> *max_len = len;
> return type;
> @@ -159,11 +162,11 @@ struct isofs_fid {
> };
>
> static struct dentry *isofs_fh_to_dentry(struct super_block *sb,
> - struct fid *fid, int fh_len, int fh_type)
> + struct fid *fid, int fh_len, enum fid_type fh_type)
> {
> struct isofs_fid *ifid = (struct isofs_fid *)fid;
>
> - if (fh_len < 3 || fh_type > 2)
> + if (fh_len < 3 || fh_type > ISOFS_FILEID_PARENT)
> return ERR_PTR(-ESTALE);
>
> return isofs_export_iget(sb, ifid->block, ifid->offset,
> @@ -171,11 +174,11 @@ static struct dentry *isofs_fh_to_dentry(struct super_block *sb,
> }
>
> static struct dentry *isofs_fh_to_parent(struct super_block *sb,
> - struct fid *fid, int fh_len, int fh_type)
> + struct fid *fid, int fh_len, enum fid_type fh_type)
> {
> struct isofs_fid *ifid = (struct isofs_fid *)fid;
>
> - if (fh_type != 2)
> + if (fh_type != ISOFS_FILEID_PARENT)
> return ERR_PTR(-ESTALE);
>
> return isofs_export_iget(sb,
> diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
> index 4c4e18c..bd4998e 100644
> --- a/fs/jffs2/super.c
> +++ b/fs/jffs2/super.c
> @@ -73,14 +73,14 @@ static struct inode *jffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
> }
>
> static struct dentry *jffs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type)
> + int fh_len, enum fid_type fh_type)
> {
> return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
> jffs2_nfs_get_inode);
> }
>
> static struct dentry *jffs2_fh_to_parent(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type)
> + int fh_len, enum fid_type fh_type)
> {
> return generic_fh_to_parent(sb, fid, fh_len, fh_type,
> jffs2_nfs_get_inode);
> diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h
> index adb2faf..aa7d573 100644
> --- a/fs/jfs/jfs_inode.h
> +++ b/fs/jfs/jfs_inode.h
> @@ -19,6 +19,7 @@
> #define _H_JFS_INODE
>
> struct fid;
> +enum fid_type;
>
> extern struct inode *ialloc(struct inode *, umode_t);
> extern int jfs_fsync(struct file *, struct dentry *, int);
> @@ -35,9 +36,9 @@ extern void jfs_free_zero_link(struct inode *);
> extern struct dentry *jfs_get_parent(struct dentry *dentry);
> extern void jfs_get_inode_flags(struct jfs_inode_info *);
> extern struct dentry *jfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type);
> + int fh_len, enum fid_type fh_type);
> extern struct dentry *jfs_fh_to_parent(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type);
> + int fh_len, enum fid_type fh_type);
> extern void jfs_set_inode_flags(struct inode *);
> extern int jfs_get_block(struct inode *, sector_t, struct buffer_head *, int);
>
> diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
> index cc3cedf..b824836 100644
> --- a/fs/jfs/namei.c
> +++ b/fs/jfs/namei.c
> @@ -1496,14 +1496,14 @@ static struct inode *jfs_nfs_get_inode(struct super_block *sb,
> }
>
> struct dentry *jfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type)
> + int fh_len, enum fid_type fh_type)
> {
> return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
> jfs_nfs_get_inode);
> }
>
> struct dentry *jfs_fh_to_parent(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type)
> + int fh_len, enum fid_type fh_type)
> {
> return generic_fh_to_parent(sb, fid, fh_len, fh_type,
> jfs_nfs_get_inode);
> diff --git a/fs/libfs.c b/fs/libfs.c
> index 47952f2..edb7e91 100644
> --- a/fs/libfs.c
> +++ b/fs/libfs.c
> @@ -745,8 +745,8 @@ out:
> * inode for the object specified in the file handle.
> */
> struct dentry *generic_fh_to_dentry(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type, struct inode *(*get_inode)
> - (struct super_block *sb, u64 ino, u32 gen))
> + int fh_len, enum fid_type fh_type,
> + exportfs_get_inode_t get_inode)
> {
> struct inode *inode = NULL;
>
> @@ -757,7 +757,6 @@ struct dentry *generic_fh_to_dentry(struct super_block *sb, struct fid *fid,
> case FILEID_INO32_GEN:
> case FILEID_INO32_GEN_PARENT:
> inode = get_inode(sb, fid->i32.ino, fid->i32.gen);
> - break;
> default:
> return ERR_PTR(-ESTALE);
> }
> @@ -780,8 +779,8 @@ EXPORT_SYMBOL_GPL(generic_fh_to_dentry);
> * is specified in the file handle, or NULL otherwise.
> */
> struct dentry *generic_fh_to_parent(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type, struct inode *(*get_inode)
> - (struct super_block *sb, u64 ino, u32 gen))
> + int fh_len, enum fid_type fh_type,
> + exportfs_get_inode_t get_inode)
> {
> struct inode *inode = NULL;
>
> @@ -792,7 +791,6 @@ struct dentry *generic_fh_to_parent(struct super_block *sb, struct fid *fid,
> case FILEID_INO32_GEN_PARENT:
> inode = get_inode(sb, fid->i32.parent_ino,
> (fh_len > 3 ? fid->i32.parent_gen : 0));
> - break;
> default:
> return ERR_PTR(-ESTALE);
> }
> diff --git a/fs/ntfs/namei.c b/fs/ntfs/namei.c
> index 2ca0015..b3826c0 100644
> --- a/fs/ntfs/namei.c
> +++ b/fs/ntfs/namei.c
> @@ -364,14 +364,14 @@ static struct inode *ntfs_nfs_get_inode(struct super_block *sb,
> }
>
> static struct dentry *ntfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type)
> + int fh_len, enum fid_type fh_type)
> {
> return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
> ntfs_nfs_get_inode);
> }
>
> static struct dentry *ntfs_fh_to_parent(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type)
> + int fh_len, enum fid_type fh_type)
> {
> return generic_fh_to_parent(sb, fid, fh_len, fh_type,
> ntfs_nfs_get_inode);
> diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c
> index 0f1c80f..c03266e 100644
> --- a/fs/ocfs2/export.c
> +++ b/fs/ocfs2/export.c
> @@ -116,12 +116,15 @@ bail:
> return parent;
> }
>
> -static int ocfs2_encode_fh(struct dentry *dentry, u32 *fh_in, int *max_len,
> - int connectable)
> +#define OCFS2_FILEID 1
> +#define OCFS2_FILEID_PARENT 2
> +
> +static enum fid_type ocfs2_encode_fh(struct dentry *dentry, u32 *fh_in,
> + int *max_len, int connectable)
> {
> struct inode *inode = dentry->d_inode;
> int len = *max_len;
> - int type = 1;
> + enum fid_type type = OCFS2_FILEID;
> u64 blkno;
> u32 generation;
> __le32 *fh = (__force __le32 *) fh_in;
> @@ -132,7 +135,7 @@ static int ocfs2_encode_fh(struct dentry *dentry, u32 *fh_in, int *max_len,
>
> if (len < 3 || (connectable && len < 6)) {
> mlog(ML_ERROR, "fh buffer is too small for encoding\n");
> - type = 255;
> + type = FILEID_ERROR;
> goto bail;
> }
>
> @@ -163,7 +166,7 @@ static int ocfs2_encode_fh(struct dentry *dentry, u32 *fh_in, int *max_len,
> spin_unlock(&dentry->d_lock);
>
> len = 6;
> - type = 2;
> + type = OCFS2_FILEID_PARENT;
>
> mlog(0, "Encoding parent: blkno: %llu, generation: %u\n",
> (unsigned long long)blkno, generation);
> @@ -177,11 +180,11 @@ bail:
> }
>
> static struct dentry *ocfs2_fh_to_dentry(struct super_block *sb,
> - struct fid *fid, int fh_len, int fh_type)
> + struct fid *fid, int fh_len, enum fid_type fh_type)
> {
> struct ocfs2_inode_handle handle;
>
> - if (fh_len < 3 || fh_type > 2)
> + if (fh_len < 3 || fh_type > OCFS2_FILEID_PARENT)
> return ERR_PTR(-ESTALE);
>
> handle.ih_blkno = (u64)le32_to_cpu(fid->raw[0]) << 32;
> @@ -191,11 +194,11 @@ static struct dentry *ocfs2_fh_to_dentry(struct super_block *sb,
> }
>
> static struct dentry *ocfs2_fh_to_parent(struct super_block *sb,
> - struct fid *fid, int fh_len, int fh_type)
> + struct fid *fid, int fh_len, enum fid_type fh_type)
> {
> struct ocfs2_inode_handle parent;
>
> - if (fh_type != 2 || fh_len < 6)
> + if (fh_type != OCFS2_FILEID_PARENT || fh_len < 6)
> return ERR_PTR(-ESTALE);
>
> parent.ih_blkno = (u64)le32_to_cpu(fid->raw[3]) << 32;
> diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
> index 6c4c2c6..3c548eb 100644
> --- a/fs/reiserfs/inode.c
> +++ b/fs/reiserfs/inode.c
> @@ -1539,7 +1539,7 @@ static struct dentry *reiserfs_get_dentry(struct super_block *sb,
> }
>
> struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type)
> + int fh_len, enum fid_type fh_type)
> {
> /* fhtype happens to reflect the number of u32s encoded.
> * due to a bug in earlier code, fhtype might indicate there
> @@ -1566,7 +1566,7 @@ struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
> }
>
> struct dentry *reiserfs_fh_to_parent(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type)
> + int fh_len, enum fid_type fh_type)
> {
> if (fh_type < 4)
> return NULL;
> @@ -1577,14 +1577,14 @@ struct dentry *reiserfs_fh_to_parent(struct super_block *sb, struct fid *fid,
> (fh_type == 6) ? fid->raw[5] : 0);
> }
>
> -int reiserfs_encode_fh(struct dentry *dentry, __u32 * data, int *lenp,
> - int need_parent)
> +enum fid_type reiserfs_encode_fh(struct dentry *dentry, __u32 * data,
> + int *lenp, int need_parent)
> {
> struct inode *inode = dentry->d_inode;
> int maxlen = *lenp;
>
> if (maxlen < 3)
> - return 255;
> + return FILEID_ERROR;
>
> data[0] = inode->i_ino;
> data[1] = le32_to_cpu(INODE_PKEY(inode)->k_dir_id);
> diff --git a/fs/udf/namei.c b/fs/udf/namei.c
> index e1a1c16..afaf45e 100644
> --- a/fs/udf/namei.c
> +++ b/fs/udf/namei.c
> @@ -1292,7 +1292,8 @@ static struct dentry *udf_nfs_get_inode(struct super_block *sb, u32 block,
> }
>
> static struct dentry *udf_fh_to_dentry(struct super_block *sb,
> - struct fid *fid, int fh_len, int fh_type)
> + struct fid *fid, int fh_len,
> + enum fid_type fh_type)
> {
> if ((fh_len != 3 && fh_len != 5) ||
> (fh_type != FILEID_UDF_WITH_PARENT &&
> @@ -1304,7 +1305,8 @@ static struct dentry *udf_fh_to_dentry(struct super_block *sb,
> }
>
> static struct dentry *udf_fh_to_parent(struct super_block *sb,
> - struct fid *fid, int fh_len, int fh_type)
> + struct fid *fid, int fh_len,
> + enum fid_type fh_type)
> {
> if (fh_len != 5 || fh_type != FILEID_UDF_WITH_PARENT)
> return ERR_PTR(-ESTALE);
> @@ -1313,17 +1315,17 @@ static struct dentry *udf_fh_to_parent(struct super_block *sb,
> fid->udf.parent_partref,
> fid->udf.parent_generation);
> }
> -static int udf_encode_fh(struct dentry *de, __u32 *fh, int *lenp,
> - int connectable)
> +static enum fid_type udf_encode_fh(struct dentry *de, __u32 *fh, int *lenp,
> + int connectable)
> {
> int len = *lenp;
> struct inode *inode = de->d_inode;
> kernel_lb_addr location = UDF_I(inode)->i_location;
> struct fid *fid = (struct fid *)fh;
> - int type = FILEID_UDF_WITHOUT_PARENT;
> + enum fid_type type = FILEID_UDF_WITHOUT_PARENT;
>
> if (len < 3 || (connectable && len < 5))
> - return 255;
> + return FILEID_ERROR;
>
> *lenp = 3;
> fid->udf.block = location.logicalBlockNum;
> diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c
> index 7a4c75f..b15d029 100644
> --- a/fs/xfs/linux-2.6/xfs_export.c
> +++ b/fs/xfs/linux-2.6/xfs_export.c
> @@ -51,7 +51,7 @@ static int xfs_fileid_length(int fileid_type)
> return 255; /* invalid */
> }
>
> -STATIC int
> +STATIC enum fid_type
> xfs_fs_encode_fh(
> struct dentry *dentry,
> __u32 *fh,
> @@ -61,7 +61,7 @@ xfs_fs_encode_fh(
> struct fid *fid = (struct fid *)fh;
> struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fh;
> struct inode *inode = dentry->d_inode;
> - int fileid_type;
> + enum fid_type fileid_type;
> int len;
>
> /* Directories don't need their parent encoded, they have ".." */
> @@ -82,7 +82,7 @@ xfs_fs_encode_fh(
> */
> len = xfs_fileid_length(fileid_type);
> if (*max_len < len)
> - return 255;
> + return FILEID_ERROR;
> *max_len = len;
>
> switch (fileid_type) {
> @@ -106,6 +106,8 @@ xfs_fs_encode_fh(
> fid64->ino = inode->i_ino;
> fid64->gen = inode->i_generation;
> break;
> + default:
> + break;
> }
>
> return fileid_type;
> @@ -144,7 +146,7 @@ xfs_nfs_get_inode(
>
> STATIC struct dentry *
> xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
> - int fh_len, int fileid_type)
> + int fh_len, enum fid_type fileid_type)
> {
> struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fid;
> struct inode *inode = NULL;
> @@ -170,7 +172,7 @@ xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
>
> STATIC struct dentry *
> xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid,
> - int fh_len, int fileid_type)
> + int fh_len, enum fid_type fileid_type)
> {
> struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fid;
> struct inode *inode = NULL;
> diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
> index 27e772c..d6995e8 100644
> --- a/include/linux/exportfs.h
> +++ b/include/linux/exportfs.h
> @@ -1,3 +1,9 @@
> +/* Persistent file handle encoding and decoding interface
> + *
> + * See Documentation/filesystems/Exporting for details on how to use this
> + * interface correctly.
> + */
> +
> #ifndef LINUX_EXPORTFS_H
> #define LINUX_EXPORTFS_H 1
>
> @@ -9,12 +15,15 @@ struct super_block;
> struct vfsmount;
>
> /*
> - * The fileid_type identifies how the file within the filesystem is encoded.
> - * In theory this is freely set and parsed by the filesystem, but we try to
> - * stick to conventions so we can share some generic code and don't confuse
> - * sniffers like ethereal/wireshark.
> + * The fid_type identifies how the parameters specifying a file within the
> + * filesystem are encoded. In theory this is freely set and parsed by the
> + * filesystem, but we try to stick to conventions so we can share some generic
> + * code and don't confuse sniffers like ethereal/wireshark.
> *
> - * The filesystem must not use the value '0' or '0xff'.
> + * The filesystem may use arbitrary values rather than picking the constants
> + * from this set, with the restriction that the values chosen must be between 1
> + * and 254. 0 and 255 are special purpose, and the value must fit within an
> + * unsigned byte.
> */
> enum fid_type {
> /*
> @@ -67,6 +76,10 @@ enum fid_type {
> * 32 bit parent block number, 32 bit parent generation number
> */
> FILEID_UDF_WITH_PARENT = 0x52,
> +
> + /* This is returned if the encode routine was unable to represent the
> + * file */
> + FILEID_ERROR = 0xff
> };
>
> struct fid {
> @@ -101,73 +114,97 @@ struct fid {
> * this interface correctly.
> *
> * encode_fh:
> - * @encode_fh should store in the file handle fragment @fh (using at most
> - * @max_len bytes) information that can be used by @decode_fh to recover the
> - * file refered to by the &struct dentry @de. If the @connectable flag is
> - * set, the encode_fh() should store sufficient information so that a good
> - * attempt can be made to find not only the file but also it's place in the
> - * filesystem. This typically means storing a reference to de->d_parent in
> - * the filehandle fragment. encode_fh() should return the number of bytes
> - * stored or a negative error code such as %-ENOSPC
> + * The @encode_fh operation should store into the file handle fragment
> + * buffer @fh at most *@max_len 32-bit words of information that can be used
> + * by fh_to_dentry() or fh_to_parent() to recover the file referred to by
> + * the &struct dentry @de.
> + *
> + * If the @connectable flag is set, the encode_fh() should store sufficient
> + * information so that a good attempt can be made to find not only the file
> + * but also it's place in the filesystem. This typically means storing a
> + * reference to de->d_parent in the filehandle fragment.
> + *
> + * On success, encode_fh() should return the type of the file handle, which
> + * the caller must retain in some manner so that it can be passed to
> + * decode_fh(). See the comment on enum fid_type as to the permitted types
> + * that may be returned. Furthermore, *max_len should be updated upon
> + * return to indicate the amount of buffer space actually filled.
> + *
> + * On failure FILEID_ERROR should be returned.
> *
> * fh_to_dentry:
> - * @fh_to_dentry is given a &struct super_block (@sb) and a file handle
> - * fragment (@fh, @fh_len). It should return a &struct dentry which refers
> - * to the same file that the file handle fragment refers to. If it cannot,
> - * it should return a %NULL pointer if the file was found but no acceptable
> - * &dentries were available, or an %ERR_PTR error code indicating why it
> - * couldn't be found (e.g. %ENOENT or %ENOMEM). Any suitable dentry can be
> - * returned including, if necessary, a new dentry created with d_alloc_root.
> - * The caller can then find any other extant dentries by following the
> - * d_alias links.
> + * The @fh_to_dentry operation is given a &struct super_block (@sb) and a
> + * file handle fragment and type (@fh, @fh_len, @fh_type). It should look
> + * up a file by the data in the partial file handle.
> + *
> + * On success, a pointer should be returned to a dentry that corresponds to
> + * the file that the file handle fragment was generated from by encode_fh().
> + * The dentry should come from the set of dentries available to the
> + * specified superblock, whether they're in memory or in storage.
> + *
> + * Any suitable dentry can be returned including, if necessary, a new dentry
> + * created with d_alloc_root. The caller can then find any other extant
> + * dentries by following the d_alias links.
> + *
> + * On failure, a negative error code should be returned indicating the
> + * reason. Note that a NULL pointer is not a valid return.
> *
> * fh_to_parent:
> * Same as @fh_to_dentry, except that it returns a pointer to the parent
> - * dentry if it was encoded into the filehandle fragment by @encode_fh.
> + * dentry if it was encoded into the filehandle fragment by encode_fh().
> *
> * get_name:
> * @get_name should find a name for the given @child in the given @parent
> * directory. The name should be stored in the @name (with the
> - * understanding that it is already pointing to a a %NAME_MAX+1 sized
> - * buffer. get_name() should return %0 on success, a negative error code
> - * or error. @get_name will be called without @parent->i_mutex held.
> + * understanding that it is already pointing to a %NAME_MAX+1 sized buffer.
> + *
> + * get_name() should return zero on success and a negative error code on
> + * failure.
> + *
> + * get_name() will be called without @parent->i_mutex held.
> *
> * get_parent:
> * @get_parent should find the parent directory for the given @child which
> * is also a directory. In the event that it cannot be found, or storage
> - * space cannot be allocated, a %ERR_PTR should be returned.
> + * space cannot be allocated, a suitable negative error code should be
> + * returned.
> *
> * Locking rules:
> * get_parent is called with child->d_inode->i_mutex down
> * get_name is not (which is possibly inconsistent)
> */
> -
> struct export_operations {
> - int (*encode_fh)(struct dentry *de, __u32 *fh, int *max_len,
> - int connectable);
> + enum fid_type (*encode_fh)(struct dentry *de, __u32 *fh, int *max_len,
> + int connectable);
> struct dentry * (*fh_to_dentry)(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type);
> + int fh_len, enum fid_type fh_type);
> struct dentry * (*fh_to_parent)(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type);
> + int fh_len, enum fid_type fh_type);
> int (*get_name)(struct dentry *parent, char *name,
> struct dentry *child);
> struct dentry * (*get_parent)(struct dentry *child);
> };
>
> -extern int exportfs_encode_fh(struct dentry *dentry, struct fid *fid,
> - int *max_len, int connectable);
> +typedef int (*exportfs_acceptable_t)(void *context, struct dentry *dentry);
> +
> +extern enum fid_type exportfs_encode_fh(struct dentry *dentry, struct fid *fid,
> + int *max_len, int connectable);
> extern struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
> - int fh_len, int fileid_type, int (*acceptable)(void *, struct dentry *),
> - void *context);
> + int fh_len, enum fid_type fileid_type,
> + exportfs_acceptable_t acceptable,
> + void *context);
>
> /*
> * Generic helpers for filesystems.
> */
> +typedef struct inode *(*exportfs_get_inode_t)(struct super_block *sb,
> + u64 ino, u32 gen);
> +
> extern struct dentry *generic_fh_to_dentry(struct super_block *sb,
> - struct fid *fid, int fh_len, int fh_type,
> - struct inode *(*get_inode) (struct super_block *sb, u64 ino, u32 gen));
> + struct fid *fid, int fh_len, enum fid_type fh_type,
> + exportfs_get_inode_t get_inode);
> extern struct dentry *generic_fh_to_parent(struct super_block *sb,
> - struct fid *fid, int fh_len, int fh_type,
> - struct inode *(*get_inode) (struct super_block *sb, u64 ino, u32 gen));
> + struct fid *fid, int fh_len, enum fid_type fh_type,
> + exportfs_get_inode_t get_inode);
>
> #endif /* LINUX_EXPORTFS_H */
> diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
> index bc5114d..0783dbe 100644
> --- a/include/linux/reiserfs_fs.h
> +++ b/include/linux/reiserfs_fs.h
> @@ -24,6 +24,7 @@
> #include <linux/proc_fs.h>
> #include <linux/smp_lock.h>
> #include <linux/buffer_head.h>
> +#include <linux/exportfs.h>
> #include <linux/reiserfs_fs_i.h>
> #include <linux/reiserfs_fs_sb.h>
> #endif
> @@ -1880,11 +1881,11 @@ int reiserfs_write_inode(struct inode *inode, int);
> int reiserfs_get_block(struct inode *inode, sector_t block,
> struct buffer_head *bh_result, int create);
> struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type);
> + int fh_len, enum fid_type fh_type);
> struct dentry *reiserfs_fh_to_parent(struct super_block *sb, struct fid *fid,
> - int fh_len, int fh_type);
> -int reiserfs_encode_fh(struct dentry *dentry, __u32 * data, int *lenp,
> - int connectable);
> + int fh_len, enum fid_type fh_type);
> +enum fid_type reiserfs_encode_fh(struct dentry *dentry, __u32 * data, int *lenp,
> + int connectable);
>
> int reiserfs_truncate_file(struct inode *, int update_timestamps);
> void make_cpu_key(struct cpu_key *cpu_key, struct inode *inode, loff_t offset,
> diff --git a/mm/shmem.c b/mm/shmem.c
> index f1b0d48..d6e91dd 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -2047,7 +2047,7 @@ static int shmem_match(struct inode *ino, void *vfh)
> }
>
> static struct dentry *shmem_fh_to_dentry(struct super_block *sb,
> - struct fid *fid, int fh_len, int fh_type)
> + struct fid *fid, int fh_len, enum fid_type fh_type)
> {
> struct inode *inode;
> struct dentry *dentry = NULL;
> @@ -2067,8 +2067,8 @@ static struct dentry *shmem_fh_to_dentry(struct super_block *sb,
> return dentry;
> }
>
> -static int shmem_encode_fh(struct dentry *dentry, __u32 *fh, int *len,
> - int connectable)
> +static enum fid_type shmem_encode_fh(struct dentry *dentry, __u32 *fh, int *len,
> + int connectable)
> {
> struct inode *inode = dentry->d_inode;
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2008-12-04 19:33 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-12-03 18:30 [PATCH 1/3] EXPORTFS: Don't return NULL from fh_to_dentry()/fh_to_parent() [try #2] David Howells
2008-12-03 18:30 ` [PATCH 2/3] EXPORTFS: Have fh_to_*() return -ESTALE if the file handle type is unrecognised " David Howells
2008-12-04 19:31 ` J. Bruce Fields
2008-12-05 9:14 ` David Howells
2008-12-03 18:30 ` [PATCH 3/3] EXPORTFS: Update the documentation and comments and adjust the types used " David Howells
2008-12-04 19:32 ` J. Bruce Fields [this message]
2008-12-05 9:09 ` David Howells
2008-12-08 23:59 ` J. Bruce Fields
2008-12-04 19:07 ` [PATCH 1/3] EXPORTFS: Don't return NULL from fh_to_dentry()/fh_to_parent() " J. Bruce Fields
2008-12-05 9:13 ` David Howells
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20081204193235.GD7575@fieldses.org \
--to=bfields@fieldses.org \
--cc=dhowells@redhat.com \
--cc=hch@infradead.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=viro@ZenIV.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.