diff options
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/super.c | 43 |
1 files changed, 40 insertions, 3 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 75f3cbf922a3..c3d8fcf38523 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -45,6 +45,8 @@ #include <linux/nfs_idmap.h> #include <linux/vfs.h> #include <linux/inet.h> +#include <linux/in6.h> +#include <net/ipv6.h> #include <linux/nfs_xdr.h> #include <linux/magic.h> #include <linux/parser.h> @@ -1326,15 +1328,50 @@ static int nfs_set_super(struct super_block *s, void *data) return ret; } +static int nfs_compare_super_address(struct nfs_server *server1, + struct nfs_server *server2) +{ + struct sockaddr *sap1, *sap2; + + sap1 = (struct sockaddr *)&server1->nfs_client->cl_addr; + sap2 = (struct sockaddr *)&server2->nfs_client->cl_addr; + + if (sap1->sa_family != sap2->sa_family) + return 0; + + switch (sap1->sa_family) { + case AF_INET: { + struct sockaddr_in *sin1 = (struct sockaddr_in *)sap1; + struct sockaddr_in *sin2 = (struct sockaddr_in *)sap2; + if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) + return 0; + if (sin1->sin_port != sin2->sin_port) + return 0; + break; + } + case AF_INET6: { + struct sockaddr_in6 *sin1 = (struct sockaddr_in6 *)sap1; + struct sockaddr_in6 *sin2 = (struct sockaddr_in6 *)sap2; + if (!ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr)) + return 0; + if (sin1->sin6_port != sin2->sin6_port) + return 0; + break; + } + default: + return 0; + } + + return 1; +} + static int nfs_compare_super(struct super_block *sb, void *data) { struct nfs_sb_mountdata *sb_mntdata = data; struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb); int mntflags = sb_mntdata->mntflags; - if (memcmp(&old->nfs_client->cl_addr, - &server->nfs_client->cl_addr, - sizeof(old->nfs_client->cl_addr)) != 0) + if (!nfs_compare_super_address(old, server)) return 0; /* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */ if (old->flags & NFS_MOUNT_UNSHARED) |