Skip to contentSkip to conversation

generic support for 64bit inodes in NFS filehandles

PATCH In review Christoph Hellwig 2 participants 2 messages Aug 11, 2008 – Aug 12, 2008

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/4 generic support for 64bit inodes in NFS filehandles

Move XFS's support for 64bit inodes in NFS filehandles to libfs. In detail:

- add the FILEID_INO64_FLAG and thei64 case in struct fid to exportfs.h
- deal with the 64bit inode cases in generic_fh_to_dentry and generic_fh_to_parent by adding them to the switch case table and rewriting the min filehandle size checks based on a readable helper
- move export_encode_fh to libfs as generic_encode_fh32 and rewrite it to be a similar style as the other exportfs functions in libfs
- add a new generic_encode_fh64 which is identical to generic_encode_fh32 except for dealing with 64bit inode filehandles

XFS is switched over to the new code, switching over other filesystems like ext4 is left to their maintainers but should be rather trivial by looking at fs/xfs/linux-2.6/xfs_export.c

fs/xfs/linux-2.6/xfs_export.c +20 -131
Index: linux-2.6/fs/xfs/linux-2.6/xfs_export.c
===================================================================
@@ -25,91 +25,10 @@
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
-#include "xfs_export.h"
 #include "xfs_vnodeops.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_inode.h"
-#include "xfs_vfsops.h"
 
-/*
- * Note that we only accept fileids which are long enough rather than allow
- * the parent generation number to default to zero.  XFS considers zero a
- * valid generation number not an invalid/wildcard value.
- */
-static int xfs_fileid_length(int fileid_type)
-{
-	switch (fileid_type) {
-	case FILEID_INO32_GEN:
-		return 2;
-	case FILEID_INO32_GEN_PARENT:
-		return 4;
-	case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
-		return 3;
-	case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
-		return 6;
-	}
-	return 255; /* invalid */
-}
-
-STATIC int
-xfs_fs_encode_fh(
-	struct dentry		*dentry,
-	__u32			*fh,
-	int			*max_len,
-	int			connectable)
-{
-	struct fid		*fid = (struct fid *)fh;
-	struct xfs_fid64	*fid64 = (struct xfs_fid64 *)fh;
-	struct inode		*inode = dentry->d_inode;
-	int			fileid_type;
-	int			len;
-
-	/* Directories don't need their parent encoded, they have ".." */
-	if (S_ISDIR(inode->i_mode) || !connectable)
-		fileid_type = FILEID_INO32_GEN;
-	else
-		fileid_type = FILEID_INO32_GEN_PARENT;
-
-	/* filesystem may contain 64bit inode numbers */
-	if (!(XFS_M(inode->i_sb)->m_flags & XFS_MOUNT_SMALL_INUMS))
-		fileid_type |= XFS_FILEID_TYPE_64FLAG;
-
-	/*
-	 * Only encode if there is enough space given.  In practice
-	 * this means we can't export a filesystem with 64bit inodes
-	 * over NFSv2 with the subtree_check export option; the other
-	 * seven combinations work.  The real answer is "don't use v2".
-	 */
-	len = xfs_fileid_length(fileid_type);
-	if (*max_len < len)
-		return 255;
-	*max_len = len;
-
-	switch (fileid_type) {
-	case FILEID_INO32_GEN_PARENT:
-		spin_lock(&dentry->d_lock);
-		fid->i32.parent_ino = dentry->d_parent->d_inode->i_ino;
-		fid->i32.parent_gen = dentry->d_parent->d_inode->i_generation;
-		spin_unlock(&dentry->d_lock);
-		/*FALLTHRU*/
-	case FILEID_INO32_GEN:
-		fid->i32.ino = inode->i_ino;
-		fid->i32.gen = inode->i_generation;
-		break;
-	case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
-		spin_lock(&dentry->d_lock);
-		fid64->parent_ino = dentry->d_parent->d_inode->i_ino;
-		fid64->parent_gen = dentry->d_parent->d_inode->i_generation;
-		spin_unlock(&dentry->d_lock);
-		/*FALLTHRU*/
-	case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
-		fid64->ino = inode->i_ino;
-		fid64->gen = inode->i_generation;
-		break;
-	}
-
-	return fileid_type;
-}
 
 STATIC struct inode *
 xfs_nfs_get_inode(
@@ -146,65 +65,35 @@ STATIC struct dentry *
 xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
 		 int fh_len, int fileid_type)
 {
-	struct xfs_fid64	*fid64 = (struct xfs_fid64 *)fid;
-	struct inode		*inode = NULL;
-	struct dentry		*result;
-
-	if (fh_len < xfs_fileid_length(fileid_type))
+	/*
+	 * We only accept fileids which are long enough rather than allow
+	 * the parent generation number to default to zero.  XFS considers
+	 * zero a valid generation number not an invalid/wildcard value.
+	 */
+	if (fileid_type == FILEID_INO32_GEN_PARENT && fh_len == 3)
 		return NULL;
 
-	switch (fileid_type) {
-	case FILEID_INO32_GEN_PARENT:
-	case FILEID_INO32_GEN:
-		inode = xfs_nfs_get_inode(sb, fid->i32.ino, fid->i32.gen);
-		break;
-	case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
-	case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG:
-		inode = xfs_nfs_get_inode(sb, fid64->ino, fid64->gen);
-		break;
-	}
-
-	if (!inode)
-		return NULL;
-	if (IS_ERR(inode))
-		return ERR_PTR(PTR_ERR(inode));
-	result = d_alloc_anon(inode);
-	if (!result) {
-		iput(inode);
-		return ERR_PTR(-ENOMEM);
-	}
-	return result;
+	return generic_fh_to_dentry(sb, fid, fh_len, fileid_type,
+			xfs_nfs_get_inode);
 }
 
 STATIC struct dentry *
 xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid,
 		 int fh_len, int fileid_type)
 {
-	struct xfs_fid64	*fid64 = (struct xfs_fid64 *)fid;
-	struct inode		*inode = NULL;
-	struct dentry		*result;
-
-	switch (fileid_type) {
-	case FILEID_INO32_GEN_PARENT:
-		inode = xfs_nfs_get_inode(sb, fid->i32.parent_ino,
-					      fid->i32.parent_gen);
-		break;
-	case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG:
-		inode = xfs_nfs_get_inode(sb, fid64->parent_ino,
-					      fid64->parent_gen);
-		break;
-	}
+	return generic_fh_to_parent(sb, fid, fh_len, fileid_type,
+			xfs_nfs_get_inode);
+}
 
-	if (!inode)
-		return NULL;
-	if (IS_ERR(inode))
-		return ERR_PTR(PTR_ERR(inode));
-	result = d_alloc_anon(inode);
-	if (!result) {
-		iput(inode);
-		return ERR_PTR(-ENOMEM);
-	}
-	return result;
+STATIC int
+xfs_fs_encode_fh(struct dentry *dentry, u32 *fh, int *max_len, int connectable)
+{
+	struct xfs_mount *mp = XFS_M(dentry->d_inode->i_sb);
+	struct fid *fid = (struct fid *)fh;
+
+	if (mp->m_flags & XFS_MOUNT_SMALL_INUMS)
+		return generic_encode_fh32(dentry, fid, max_len, connectable);
+	return generic_encode_fh64(dentry, fid, max_len, connectable);
 }
 
 STATIC struct dentry *
fs/xfs/linux-2.6/xfs_export.h deleted +0 -72

72 lines not on this page · raw message

include/linux/exportfs.h +16 -0
Index: linux-2.6/include/linux/exportfs.h
===================================================================
@@ -46,6 +46,12 @@ enum fid_type {
 	 * 32 bit parent block number, 32 bit parent generation number
 	 */
 	FILEID_UDF_WITH_PARENT = 0x52,
+
+	/*
+	 * Flag to state we have 64bit inode numbers.
+	 * This flag is ored into the 32bit filehande types.
+	 */
+	FILEID_INO64_FLAG = 0x80,
 };
 
 struct fid {
@@ -56,6 +62,12 @@ struct fid {
 			u32 parent_ino;
 			u32 parent_gen;
 		} i32;
+		struct {
+			u64 ino;
+			u32 gen;
+			u64 parent_ino;
+			u32 parent_gen;
+		} i64;
  		struct {
  			u32 block;
  			u16 partref;
@@ -148,5 +160,9 @@ extern struct dentry *generic_fh_to_dent
 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));
+extern int generic_encode_fh32(struct dentry *dentry, struct fid *fid,
+	int *max_len, int connectable);
+extern int generic_encode_fh64(struct dentry *dentry, struct fid *fid,
+	int *max_len, int connectable);
 
 #endif /* LINUX_EXPORTFS_H */
fs/libfs.c +142 -5

188 lines not on this page · raw message

fs/exportfs/expfs.c +1 -41

54 lines not on this page · raw message

#1 lore raw
Quoted 14 lines · Christoph Hellwig

Move XFS's support for 64bit inodes in NFS filehandles to libfs. In detail:

- add the FILEID_INO64_FLAG and thei64 case in struct fid to exportfs.h
- deal with the 64bit inode cases in generic_fh_to_dentry and generic_fh_to_parent by adding them to the switch case table and rewriting the min filehandle size checks based on a readable helper
- move export_encode_fh to libfs as generic_encode_fh32 and rewrite it to be a similar style as the other exportfs functions in libfs
- add a new generic_encode_fh64 which is identical to generic_encode_fh32 except for dealing with 64bit inode filehandles

Quoted 3 lines

XFS is switched over to the new code, switching over other filesystems like ext4 is left to their maintainers but should be rather trivial by looking at fs/xfs/linux-2.6/xfs_export.c

The XFS->generic conversion looks OK to me....

Cheers,

Dave.

Signature · 2 lines
Dave Chinner
[email protected]