diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2007-12-10 14:57:38 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-01-30 02:05:53 -0500 |
commit | fd00a8ff8e37815c9df49f5cf09786e441e1396b (patch) | |
tree | b6e4caf750834591c0991f9aa55b26f1f02b530d /fs | |
parent | 3f43c6667acb4e02962b2829a4d4ebb6b6e6f70e (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.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 @@ | |||
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 | ||
1331 | static 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 | |||
1329 | static int nfs_compare_super(struct super_block *sb, void *data) | 1368 | static 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) |