aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2007-12-10 14:57:38 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2008-01-30 02:05:53 -0500
commitfd00a8ff8e37815c9df49f5cf09786e441e1396b (patch)
treeb6e4caf750834591c0991f9aa55b26f1f02b530d /fs
parent3f43c6667acb4e02962b2829a4d4ebb6b6e6f70e (diff)
NFS: Add support for AF_INET6 addresses in nfs_compare_super()
Refactor nfs_compare_super() and add AF_INET6 support. Replace the generic memcmp() to document explicitly what parts of the addresses must match in this check, and make the comparison independent of the lengths of both addresses. A side benefit is both tests are more computationally efficient than a memcmp(). Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/super.c43
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 @@
45#include <linux/nfs_idmap.h> 45#include <linux/nfs_idmap.h>
46#include <linux/vfs.h> 46#include <linux/vfs.h>
47#include <linux/inet.h> 47#include <linux/inet.h>
48#include <linux/in6.h>
49#include <net/ipv6.h>
48#include <linux/nfs_xdr.h> 50#include <linux/nfs_xdr.h>
49#include <linux/magic.h> 51#include <linux/magic.h>
50#include <linux/parser.h> 52#include <linux/parser.h>
@@ -1326,15 +1328,50 @@ static int nfs_set_super(struct super_block *s, void *data)
1326 return ret; 1328 return ret;
1327} 1329}
1328 1330
1331static int nfs_compare_super_address(struct nfs_server *server1,
1332 struct nfs_server *server2)
1333{
1334 struct sockaddr *sap1, *sap2;
1335
1336 sap1 = (struct sockaddr *)&server1->nfs_client->cl_addr;
1337 sap2 = (struct sockaddr *)&server2->nfs_client->cl_addr;
1338
1339 if (sap1->sa_family != sap2->sa_family)
1340 return 0;
1341
1342 switch (sap1->sa_family) {
1343 case AF_INET: {
1344 struct sockaddr_in *sin1 = (struct sockaddr_in *)sap1;
1345 struct sockaddr_in *sin2 = (struct sockaddr_in *)sap2;
1346 if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr)
1347 return 0;
1348 if (sin1->sin_port != sin2->sin_port)
1349 return 0;
1350 break;
1351 }
1352 case AF_INET6: {
1353 struct sockaddr_in6 *sin1 = (struct sockaddr_in6 *)sap1;
1354 struct sockaddr_in6 *sin2 = (struct sockaddr_in6 *)sap2;
1355 if (!ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr))
1356 return 0;
1357 if (sin1->sin6_port != sin2->sin6_port)
1358 return 0;
1359 break;
1360 }
1361 default:
1362 return 0;
1363 }
1364
1365 return 1;
1366}
1367
1329static int nfs_compare_super(struct super_block *sb, void *data) 1368static int nfs_compare_super(struct super_block *sb, void *data)
1330{ 1369{
1331 struct nfs_sb_mountdata *sb_mntdata = data; 1370 struct nfs_sb_mountdata *sb_mntdata = data;
1332 struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb); 1371 struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb);
1333 int mntflags = sb_mntdata->mntflags; 1372 int mntflags = sb_mntdata->mntflags;
1334 1373
1335 if (memcmp(&old->nfs_client->cl_addr, 1374 if (!nfs_compare_super_address(old, server))
1336 &server->nfs_client->cl_addr,
1337 sizeof(old->nfs_client->cl_addr)) != 0)
1338 return 0; 1375 return 0;
1339 /* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */ 1376 /* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */
1340 if (old->flags & NFS_MOUNT_UNSHARED) 1377 if (old->flags & NFS_MOUNT_UNSHARED)