While the storage container for NFS file handles must be able to store 128 bytes, usually NFS servers don't use file handles that are more than 32 bytes in size. This patch creates an efficient mechanism for comparing file handles that ignores the unused bytes in a file handle. Patch against 2.6.7-rc3. fs/lockd/svcsubs.c | 2 +- fs/nfs/dir.c | 4 ++-- fs/nfs/inode.c | 4 ++-- include/linux/nfs.h | 13 +++++++++++++ 4 files changed, 18 insertions(+), 5 deletions(-) Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust diff -X /home/cel/src/linux/dont-diff -Naurp 04-nfsi-req_lock/fs/lockd/svcsubs.c 05-nfs_fh_compare/fs/lockd/svcsubs.c --- 04-nfsi-req_lock/fs/lockd/svcsubs.c 2004-05-09 22:32:52.000000000 -0400 +++ 05-nfs_fh_compare/fs/lockd/svcsubs.c 2004-06-08 17:36:31.449506000 -0400 @@ -67,7 +67,7 @@ nlm_lookup_file(struct svc_rqst *rqstp, down(&nlm_file_sema); for (file = nlm_files[hash]; file; file = file->f_next) - if (!memcmp(&file->f_handle, f, sizeof(*f))) + if (!nfs_compare_fh(&file->f_handle, f)) goto found; dprintk("lockd: creating file for (%08x %08x %08x %08x %08x %08x)\n", diff -X /home/cel/src/linux/dont-diff -Naurp 04-nfsi-req_lock/fs/nfs/dir.c 05-nfs_fh_compare/fs/nfs/dir.c --- 04-nfsi-req_lock/fs/nfs/dir.c 2004-06-08 17:30:41.292158000 -0400 +++ 05-nfs_fh_compare/fs/nfs/dir.c 2004-06-08 17:36:31.454506000 -0400 @@ -610,7 +610,7 @@ static int nfs_lookup_revalidate(struct verifier = nfs_save_change_attribute(dir); error = nfs_cached_lookup(dir, dentry, &fhandle, &fattr); if (!error) { - if (memcmp(NFS_FH(inode), &fhandle, sizeof(struct nfs_fh))!= 0) + if (nfs_compare_fh(NFS_FH(inode), &fhandle)) goto out_bad; if (nfs_lookup_verify_inode(inode, isopen)) goto out_zap_parent; @@ -623,7 +623,7 @@ static int nfs_lookup_revalidate(struct error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); if (error) goto out_bad; - if (memcmp(NFS_FH(inode), &fhandle, sizeof(struct nfs_fh))!= 0) + if (nfs_compare_fh(NFS_FH(inode), &fhandle)) goto out_bad; if ((error = nfs_refresh_inode(inode, &fattr)) != 0) goto out_bad; diff -X /home/cel/src/linux/dont-diff -Naurp 04-nfsi-req_lock/fs/nfs/inode.c 05-nfs_fh_compare/fs/nfs/inode.c --- 04-nfsi-req_lock/fs/nfs/inode.c 2004-06-08 17:34:43.192398000 -0400 +++ 05-nfs_fh_compare/fs/nfs/inode.c 2004-06-08 17:36:31.476506000 -0400 @@ -598,7 +598,7 @@ nfs_find_actor(struct inode *inode, void if (NFS_FILEID(inode) != fattr->fileid) return 0; - if (memcmp(NFS_FH(inode), fh, sizeof(struct nfs_fh)) != 0) + if (nfs_compare_fh(NFS_FH(inode), fh)) return 0; if (is_bad_inode(inode)) return 0; @@ -1264,7 +1264,7 @@ static int nfs_compare_super(struct supe return 0; if (old->addr.sin_port != server->addr.sin_port) return 0; - return !memcmp(&old->fh, &server->fh, sizeof(struct nfs_fh)); + return !nfs_compare_fh(&old->fh, &server->fh); } static struct super_block *nfs_get_sb(struct file_system_type *fs_type, diff -X /home/cel/src/linux/dont-diff -Naurp 04-nfsi-req_lock/include/linux/nfs.h 05-nfs_fh_compare/include/linux/nfs.h --- 04-nfsi-req_lock/include/linux/nfs.h 2004-05-09 22:33:05.000000000 -0400 +++ 05-nfs_fh_compare/include/linux/nfs.h 2004-06-08 17:36:31.480509000 -0400 @@ -8,6 +8,7 @@ #define _LINUX_NFS_H #include +#include #define NFS_PROGRAM 100003 #define NFS_PORT 2049 @@ -139,6 +140,16 @@ struct nfs_fh { }; /* + * Returns a zero iff the size and data fields match. + * Checks only "size" bytes in the data field. + */ +static inline int nfs_compare_fh(const struct nfs_fh *a, const struct nfs_fh *b) +{ + return a->size != b->size || memcmp(a->data, b->data, a->size) != 0; +} + + +/* * This is really a general kernel constant, but since nothing like * this is defined in the kernel headers, I have to do it here. */