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). Signed-off-by: David Howells <dhowells@xxxxxxxxxx> --- 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@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html