* [PATCH 1/3] EXPORTFS: Don't return NULL from fh_to_dentry()/fh_to_parent() [try #2]
@ 2008-12-03 18:30 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
` (3 more replies)
0 siblings, 4 replies; 10+ messages in thread
From: David Howells @ 2008-12-03 18:30 UTC (permalink / raw)
To: hch, viro; +Cc: dhowells, linux-fsdevel
Returning NULL from fh_to_dentry() and fh_to_parent() is not permitted, so
return -ESTALE instead. exportfs_decode_fh() does not check for NULL, but
will try to dereference it as IS_ERR() does not check for it.
The generic_fh_to_dentry() and generic_fh_to_parent() functions also no longer
return NULL, but return -ESTALE instead.
Signed-off-by: David Howells <dhowells@redhat.com>
---
fs/fat/inode.c | 2 +-
fs/fuse/inode.c | 4 ++--
fs/gfs2/ops_export.c | 4 ++--
fs/isofs/export.c | 4 ++--
fs/libfs.c | 4 ++--
fs/ocfs2/export.c | 4 ++--
fs/udf/namei.c | 4 ++--
fs/xfs/linux-2.6/xfs_export.c | 2 +-
8 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index d937aaf..cac84f2 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -657,7 +657,7 @@ static struct dentry *fat_fh_to_dentry(struct super_block *sb,
u32 *fh = fid->raw;
if (fh_len < 5 || fh_type != 3)
- return NULL;
+ return ERR_PTR(-ESTALE);
inode = ilookup(sb, fh[0]);
if (!inode || inode->i_generation != fh[1]) {
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 2e99f34..0eb8990 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -653,7 +653,7 @@ static struct dentry *fuse_fh_to_dentry(struct super_block *sb,
struct fuse_inode_handle handle;
if ((fh_type != 0x81 && fh_type != 0x82) || fh_len < 3)
- return NULL;
+ return ERR_PTR(-ESTALE);
handle.nodeid = (u64) fid->raw[0] << 32;
handle.nodeid |= (u64) fid->raw[1];
@@ -667,7 +667,7 @@ static struct dentry *fuse_fh_to_parent(struct super_block *sb,
struct fuse_inode_handle parent;
if (fh_type != 0x82 || fh_len < 6)
- return NULL;
+ return ERR_PTR(-ESTALE);
parent.nodeid = (u64) fid->raw[3] << 32;
parent.nodeid |= (u64) fid->raw[4];
diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c
index bbb8c36..2864873 100644
--- a/fs/gfs2/ops_export.c
+++ b/fs/gfs2/ops_export.c
@@ -254,7 +254,7 @@ static struct dentry *gfs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
this.no_addr |= be32_to_cpu(fh[3]);
return gfs2_get_dentry(sb, &this);
default:
- return NULL;
+ return ERR_PTR(-ESTALE);
}
}
@@ -273,7 +273,7 @@ static struct dentry *gfs2_fh_to_parent(struct super_block *sb, struct fid *fid,
parent.no_addr |= be32_to_cpu(fh[7]);
return gfs2_get_dentry(sb, &parent);
default:
- return NULL;
+ return ERR_PTR(-ESTALE);
}
}
diff --git a/fs/isofs/export.c b/fs/isofs/export.c
index e81a305..1b4ee23 100644
--- a/fs/isofs/export.c
+++ b/fs/isofs/export.c
@@ -164,7 +164,7 @@ static struct dentry *isofs_fh_to_dentry(struct super_block *sb,
struct isofs_fid *ifid = (struct isofs_fid *)fid;
if (fh_len < 3 || fh_type > 2)
- return NULL;
+ return ERR_PTR(-ESTALE);
return isofs_export_iget(sb, ifid->block, ifid->offset,
ifid->generation);
@@ -176,7 +176,7 @@ static struct dentry *isofs_fh_to_parent(struct super_block *sb,
struct isofs_fid *ifid = (struct isofs_fid *)fid;
if (fh_type != 2)
- return NULL;
+ return ERR_PTR(-ESTALE);
return isofs_export_iget(sb,
fh_len > 2 ? ifid->parent_block : 0,
diff --git a/fs/libfs.c b/fs/libfs.c
index e960a83..4fe5b5b 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -751,7 +751,7 @@ struct dentry *generic_fh_to_dentry(struct super_block *sb, struct fid *fid,
struct inode *inode = NULL;
if (fh_len < 2)
- return NULL;
+ return ERR_PTR(-ESTALE);
switch (fh_type) {
case FILEID_INO32_GEN:
@@ -784,7 +784,7 @@ struct dentry *generic_fh_to_parent(struct super_block *sb, struct fid *fid,
struct inode *inode = NULL;
if (fh_len <= 2)
- return NULL;
+ return ERR_PTR(-ESTALE);
switch (fh_type) {
case FILEID_INO32_GEN_PARENT:
diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c
index 2f27b33..0f1c80f 100644
--- a/fs/ocfs2/export.c
+++ b/fs/ocfs2/export.c
@@ -182,7 +182,7 @@ static struct dentry *ocfs2_fh_to_dentry(struct super_block *sb,
struct ocfs2_inode_handle handle;
if (fh_len < 3 || fh_type > 2)
- return NULL;
+ return ERR_PTR(-ESTALE);
handle.ih_blkno = (u64)le32_to_cpu(fid->raw[0]) << 32;
handle.ih_blkno |= (u64)le32_to_cpu(fid->raw[1]);
@@ -196,7 +196,7 @@ static struct dentry *ocfs2_fh_to_parent(struct super_block *sb,
struct ocfs2_inode_handle parent;
if (fh_type != 2 || fh_len < 6)
- return NULL;
+ return ERR_PTR(-ESTALE);
parent.ih_blkno = (u64)le32_to_cpu(fid->raw[3]) << 32;
parent.ih_blkno |= (u64)le32_to_cpu(fid->raw[4]);
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index f84bfaa..e1a1c16 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -1297,7 +1297,7 @@ static struct dentry *udf_fh_to_dentry(struct super_block *sb,
if ((fh_len != 3 && fh_len != 5) ||
(fh_type != FILEID_UDF_WITH_PARENT &&
fh_type != FILEID_UDF_WITHOUT_PARENT))
- return NULL;
+ return ERR_PTR(-ESTALE);
return udf_nfs_get_inode(sb, fid->udf.block, fid->udf.partref,
fid->udf.generation);
@@ -1307,7 +1307,7 @@ static struct dentry *udf_fh_to_parent(struct super_block *sb,
struct fid *fid, int fh_len, int fh_type)
{
if (fh_len != 5 || fh_type != FILEID_UDF_WITH_PARENT)
- return NULL;
+ return ERR_PTR(-ESTALE);
return udf_nfs_get_inode(sb, fid->udf.parent_block,
fid->udf.parent_partref,
diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c
index 7f7abec..f9a51c4 100644
--- a/fs/xfs/linux-2.6/xfs_export.c
+++ b/fs/xfs/linux-2.6/xfs_export.c
@@ -150,7 +150,7 @@ xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
struct inode *inode = NULL;
if (fh_len < xfs_fileid_length(fileid_type))
- return NULL;
+ return ERR_PTR(-ESTALE);
switch (fileid_type) {
case FILEID_INO32_GEN_PARENT:
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/3] EXPORTFS: Have fh_to_*() return -ESTALE if the file handle type is unrecognised [try #2]
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 ` 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
` (2 subsequent siblings)
3 siblings, 2 replies; 10+ messages in thread
From: David Howells @ 2008-12-03 18:30 UTC (permalink / raw)
To: hch, viro; +Cc: dhowells, linux-fsdevel
Make fh_to_dentry() and fh_to_parent() operations return -ESTALE rather than a
negative dentry if the file handle type is unrecognised.
Signed-off-by: David Howells <dhowells@redhat.com>
---
fs/libfs.c | 4 ++++
fs/xfs/linux-2.6/xfs_export.c | 4 ++++
2 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/fs/libfs.c b/fs/libfs.c
index 4fe5b5b..47952f2 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -758,6 +758,8 @@ struct dentry *generic_fh_to_dentry(struct super_block *sb, struct fid *fid,
case FILEID_INO32_GEN_PARENT:
inode = get_inode(sb, fid->i32.ino, fid->i32.gen);
break;
+ default:
+ return ERR_PTR(-ESTALE);
}
return d_obtain_alias(inode);
@@ -791,6 +793,8 @@ struct dentry *generic_fh_to_parent(struct super_block *sb, struct fid *fid,
inode = get_inode(sb, fid->i32.parent_ino,
(fh_len > 3 ? fid->i32.parent_gen : 0));
break;
+ default:
+ return ERR_PTR(-ESTALE);
}
return d_obtain_alias(inode);
diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c
index f9a51c4..7a4c75f 100644
--- a/fs/xfs/linux-2.6/xfs_export.c
+++ b/fs/xfs/linux-2.6/xfs_export.c
@@ -161,6 +161,8 @@ xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
inode = xfs_nfs_get_inode(sb, fid64->ino, fid64->gen);
break;
+ default:
+ return ERR_PTR(-ESTALE);
}
return d_obtain_alias(inode);
@@ -182,6 +184,8 @@ xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid,
inode = xfs_nfs_get_inode(sb, fid64->parent_ino,
fid64->parent_gen);
break;
+ default:
+ return ERR_PTR(-ESTALE);
}
return d_obtain_alias(inode);
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/3] EXPORTFS: Update the documentation and comments and adjust the types used [try #2]
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-03 18:30 ` David Howells
2008-12-04 19:32 ` J. Bruce Fields
2008-12-05 9:09 ` David Howells
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
3 siblings, 2 replies; 10+ messages in thread
From: David Howells @ 2008-12-03 18:30 UTC (permalink / raw)
To: hch, viro; +Cc: dhowells, linux-fsdevel
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@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;
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 1/3] EXPORTFS: Don't return NULL from fh_to_dentry()/fh_to_parent() [try #2]
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-03 18:30 ` [PATCH 3/3] EXPORTFS: Update the documentation and comments and adjust the types used " David Howells
@ 2008-12-04 19:07 ` J. Bruce Fields
2008-12-05 9:13 ` David Howells
3 siblings, 0 replies; 10+ messages in thread
From: J. Bruce Fields @ 2008-12-04 19:07 UTC (permalink / raw)
To: David Howells; +Cc: hch, viro, linux-fsdevel
On Wed, Dec 03, 2008 at 06:30:33PM +0000, David Howells wrote:
> Returning NULL from fh_to_dentry() and fh_to_parent() is not permitted, so
> return -ESTALE instead. exportfs_decode_fh() does not check for NULL, but
> will try to dereference it as IS_ERR() does not check for it.
>
> The generic_fh_to_dentry() and generic_fh_to_parent() functions also no longer
> return NULL, but return -ESTALE instead.
Makes sense to me:
Acked-by: J. Bruce Fields <bfields@citi.umich.edu>
So the bug was introduced by 440037287c5 "[PATCH] switch all filesystems
over to d_obtain_alias"?
I think this should go into 2.6.28.
--b.
>
> Signed-off-by: David Howells <dhowells@redhat.com>
> ---
>
> fs/fat/inode.c | 2 +-
> fs/fuse/inode.c | 4 ++--
> fs/gfs2/ops_export.c | 4 ++--
> fs/isofs/export.c | 4 ++--
> fs/libfs.c | 4 ++--
> fs/ocfs2/export.c | 4 ++--
> fs/udf/namei.c | 4 ++--
> fs/xfs/linux-2.6/xfs_export.c | 2 +-
> 8 files changed, 14 insertions(+), 14 deletions(-)
>
>
> diff --git a/fs/fat/inode.c b/fs/fat/inode.c
> index d937aaf..cac84f2 100644
> --- a/fs/fat/inode.c
> +++ b/fs/fat/inode.c
> @@ -657,7 +657,7 @@ static struct dentry *fat_fh_to_dentry(struct super_block *sb,
> u32 *fh = fid->raw;
>
> if (fh_len < 5 || fh_type != 3)
> - return NULL;
> + return ERR_PTR(-ESTALE);
>
> inode = ilookup(sb, fh[0]);
> if (!inode || inode->i_generation != fh[1]) {
> diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
> index 2e99f34..0eb8990 100644
> --- a/fs/fuse/inode.c
> +++ b/fs/fuse/inode.c
> @@ -653,7 +653,7 @@ static struct dentry *fuse_fh_to_dentry(struct super_block *sb,
> struct fuse_inode_handle handle;
>
> if ((fh_type != 0x81 && fh_type != 0x82) || fh_len < 3)
> - return NULL;
> + return ERR_PTR(-ESTALE);
>
> handle.nodeid = (u64) fid->raw[0] << 32;
> handle.nodeid |= (u64) fid->raw[1];
> @@ -667,7 +667,7 @@ static struct dentry *fuse_fh_to_parent(struct super_block *sb,
> struct fuse_inode_handle parent;
>
> if (fh_type != 0x82 || fh_len < 6)
> - return NULL;
> + return ERR_PTR(-ESTALE);
>
> parent.nodeid = (u64) fid->raw[3] << 32;
> parent.nodeid |= (u64) fid->raw[4];
> diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c
> index bbb8c36..2864873 100644
> --- a/fs/gfs2/ops_export.c
> +++ b/fs/gfs2/ops_export.c
> @@ -254,7 +254,7 @@ static struct dentry *gfs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
> this.no_addr |= be32_to_cpu(fh[3]);
> return gfs2_get_dentry(sb, &this);
> default:
> - return NULL;
> + return ERR_PTR(-ESTALE);
> }
> }
>
> @@ -273,7 +273,7 @@ static struct dentry *gfs2_fh_to_parent(struct super_block *sb, struct fid *fid,
> parent.no_addr |= be32_to_cpu(fh[7]);
> return gfs2_get_dentry(sb, &parent);
> default:
> - return NULL;
> + return ERR_PTR(-ESTALE);
> }
> }
>
> diff --git a/fs/isofs/export.c b/fs/isofs/export.c
> index e81a305..1b4ee23 100644
> --- a/fs/isofs/export.c
> +++ b/fs/isofs/export.c
> @@ -164,7 +164,7 @@ static struct dentry *isofs_fh_to_dentry(struct super_block *sb,
> struct isofs_fid *ifid = (struct isofs_fid *)fid;
>
> if (fh_len < 3 || fh_type > 2)
> - return NULL;
> + return ERR_PTR(-ESTALE);
>
> return isofs_export_iget(sb, ifid->block, ifid->offset,
> ifid->generation);
> @@ -176,7 +176,7 @@ static struct dentry *isofs_fh_to_parent(struct super_block *sb,
> struct isofs_fid *ifid = (struct isofs_fid *)fid;
>
> if (fh_type != 2)
> - return NULL;
> + return ERR_PTR(-ESTALE);
>
> return isofs_export_iget(sb,
> fh_len > 2 ? ifid->parent_block : 0,
> diff --git a/fs/libfs.c b/fs/libfs.c
> index e960a83..4fe5b5b 100644
> --- a/fs/libfs.c
> +++ b/fs/libfs.c
> @@ -751,7 +751,7 @@ struct dentry *generic_fh_to_dentry(struct super_block *sb, struct fid *fid,
> struct inode *inode = NULL;
>
> if (fh_len < 2)
> - return NULL;
> + return ERR_PTR(-ESTALE);
>
> switch (fh_type) {
> case FILEID_INO32_GEN:
> @@ -784,7 +784,7 @@ struct dentry *generic_fh_to_parent(struct super_block *sb, struct fid *fid,
> struct inode *inode = NULL;
>
> if (fh_len <= 2)
> - return NULL;
> + return ERR_PTR(-ESTALE);
>
> switch (fh_type) {
> case FILEID_INO32_GEN_PARENT:
> diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c
> index 2f27b33..0f1c80f 100644
> --- a/fs/ocfs2/export.c
> +++ b/fs/ocfs2/export.c
> @@ -182,7 +182,7 @@ static struct dentry *ocfs2_fh_to_dentry(struct super_block *sb,
> struct ocfs2_inode_handle handle;
>
> if (fh_len < 3 || fh_type > 2)
> - return NULL;
> + return ERR_PTR(-ESTALE);
>
> handle.ih_blkno = (u64)le32_to_cpu(fid->raw[0]) << 32;
> handle.ih_blkno |= (u64)le32_to_cpu(fid->raw[1]);
> @@ -196,7 +196,7 @@ static struct dentry *ocfs2_fh_to_parent(struct super_block *sb,
> struct ocfs2_inode_handle parent;
>
> if (fh_type != 2 || fh_len < 6)
> - return NULL;
> + return ERR_PTR(-ESTALE);
>
> parent.ih_blkno = (u64)le32_to_cpu(fid->raw[3]) << 32;
> parent.ih_blkno |= (u64)le32_to_cpu(fid->raw[4]);
> diff --git a/fs/udf/namei.c b/fs/udf/namei.c
> index f84bfaa..e1a1c16 100644
> --- a/fs/udf/namei.c
> +++ b/fs/udf/namei.c
> @@ -1297,7 +1297,7 @@ static struct dentry *udf_fh_to_dentry(struct super_block *sb,
> if ((fh_len != 3 && fh_len != 5) ||
> (fh_type != FILEID_UDF_WITH_PARENT &&
> fh_type != FILEID_UDF_WITHOUT_PARENT))
> - return NULL;
> + return ERR_PTR(-ESTALE);
>
> return udf_nfs_get_inode(sb, fid->udf.block, fid->udf.partref,
> fid->udf.generation);
> @@ -1307,7 +1307,7 @@ static struct dentry *udf_fh_to_parent(struct super_block *sb,
> struct fid *fid, int fh_len, int fh_type)
> {
> if (fh_len != 5 || fh_type != FILEID_UDF_WITH_PARENT)
> - return NULL;
> + return ERR_PTR(-ESTALE);
>
> return udf_nfs_get_inode(sb, fid->udf.parent_block,
> fid->udf.parent_partref,
> diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c
> index 7f7abec..f9a51c4 100644
> --- a/fs/xfs/linux-2.6/xfs_export.c
> +++ b/fs/xfs/linux-2.6/xfs_export.c
> @@ -150,7 +150,7 @@ xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
> struct inode *inode = NULL;
>
> if (fh_len < xfs_fileid_length(fileid_type))
> - return NULL;
> + return ERR_PTR(-ESTALE);
>
> switch (fileid_type) {
> case FILEID_INO32_GEN_PARENT:
>
> --
> 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
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/3] EXPORTFS: Have fh_to_*() return -ESTALE if the file handle type is unrecognised [try #2]
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
1 sibling, 0 replies; 10+ messages in thread
From: J. Bruce Fields @ 2008-12-04 19:31 UTC (permalink / raw)
To: David Howells; +Cc: hch, viro, linux-fsdevel
On Wed, Dec 03, 2008 at 06:30:38PM +0000, David Howells wrote:
> Make fh_to_dentry() and fh_to_parent() operations return -ESTALE rather than a
> negative dentry if the file handle type is unrecognised.
>
> Signed-off-by: David Howells <dhowells@redhat.com>
> ---
>
> fs/libfs.c | 4 ++++
> fs/xfs/linux-2.6/xfs_export.c | 4 ++++
> 2 files changed, 8 insertions(+), 0 deletions(-)
>
>
> diff --git a/fs/libfs.c b/fs/libfs.c
> index 4fe5b5b..47952f2 100644
> --- a/fs/libfs.c
> +++ b/fs/libfs.c
> @@ -758,6 +758,8 @@ struct dentry *generic_fh_to_dentry(struct super_block *sb, struct fid *fid,
> case FILEID_INO32_GEN_PARENT:
> inode = get_inode(sb, fid->i32.ino, fid->i32.gen);
> break;
> + default:
> + return ERR_PTR(-ESTALE);
> }
>
> return d_obtain_alias(inode);
It looks like d_obtain_alias already returns -ESTALE in this case, not a
negative dentry.
> @@ -791,6 +793,8 @@ struct dentry *generic_fh_to_parent(struct super_block *sb, struct fid *fid,
> inode = get_inode(sb, fid->i32.parent_ino,
> (fh_len > 3 ? fid->i32.parent_gen : 0));
> break;
> + default:
> + return ERR_PTR(-ESTALE);
> }
>
> return d_obtain_alias(inode);
Ditto here, and in the other two cases. I don't understand what you're
doing.
--b.
> diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c
> index f9a51c4..7a4c75f 100644
> --- a/fs/xfs/linux-2.6/xfs_export.c
> +++ b/fs/xfs/linux-2.6/xfs_export.c
> @@ -161,6 +161,8 @@ xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
> case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
> inode = xfs_nfs_get_inode(sb, fid64->ino, fid64->gen);
> break;
> + default:
> + return ERR_PTR(-ESTALE);
> }
>
> return d_obtain_alias(inode);
> @@ -182,6 +184,8 @@ xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid,
> inode = xfs_nfs_get_inode(sb, fid64->parent_ino,
> fid64->parent_gen);
> break;
> + default:
> + return ERR_PTR(-ESTALE);
> }
>
> return d_obtain_alias(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
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 3/3] EXPORTFS: Update the documentation and comments and adjust the types used [try #2]
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
2008-12-05 9:09 ` David Howells
1 sibling, 0 replies; 10+ messages in thread
From: J. Bruce Fields @ 2008-12-04 19:32 UTC (permalink / raw)
To: David Howells; +Cc: hch, viro, linux-fsdevel
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
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 3/3] EXPORTFS: Update the documentation and comments and adjust the types used [try #2]
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
@ 2008-12-05 9:09 ` David Howells
2008-12-08 23:59 ` J. Bruce Fields
1 sibling, 1 reply; 10+ messages in thread
From: David Howells @ 2008-12-05 9:09 UTC (permalink / raw)
To: J. Bruce Fields; +Cc: dhowells, hch, viro, linux-fsdevel
J. Bruce Fields <bfields@fieldses.org> wrote:
> Could we get separate patches for these?
For every individual change?
David
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/3] EXPORTFS: Don't return NULL from fh_to_dentry()/fh_to_parent() [try #2]
2008-12-03 18:30 [PATCH 1/3] EXPORTFS: Don't return NULL from fh_to_dentry()/fh_to_parent() [try #2] David Howells
` (2 preceding siblings ...)
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
3 siblings, 0 replies; 10+ messages in thread
From: David Howells @ 2008-12-05 9:13 UTC (permalink / raw)
To: J. Bruce Fields; +Cc: dhowells, hch, viro, linux-fsdevel
J. Bruce Fields <bfields@fieldses.org> wrote:
> I think this should go into 2.6.28.
I've posted it to Linus.
David
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/3] EXPORTFS: Have fh_to_*() return -ESTALE if the file handle type is unrecognised [try #2]
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
1 sibling, 0 replies; 10+ messages in thread
From: David Howells @ 2008-12-05 9:14 UTC (permalink / raw)
To: J. Bruce Fields; +Cc: dhowells, hch, viro, linux-fsdevel
J. Bruce Fields <bfields@fieldses.org> wrote:
> It looks like d_obtain_alias already returns -ESTALE in this case, not a
> negative dentry.
Sorry, you're right. I should know that. This patch is superfluous, though
it may give better performance in the duff-handle case.
David
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 3/3] EXPORTFS: Update the documentation and comments and adjust the types used [try #2]
2008-12-05 9:09 ` David Howells
@ 2008-12-08 23:59 ` J. Bruce Fields
0 siblings, 0 replies; 10+ messages in thread
From: J. Bruce Fields @ 2008-12-08 23:59 UTC (permalink / raw)
To: David Howells; +Cc: hch, viro, linux-fsdevel
On Fri, Dec 05, 2008 at 09:09:14AM +0000, David Howells wrote:
> J. Bruce Fields <bfields@fieldses.org> wrote:
>
> > Could we get separate patches for these?
>
> For every individual change?
No, I don't object to some degree of bundling together pure cleanups,
but this was getting a bit long.
In the case of a trivial patch I really like being able to look at the
description, look down at the patch, and see that it obviously does
what's described, without having to hunt around.
--b.
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2008-12-08 23:59 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).