diff options
author | rmacklem <rmacklem@FreeBSD.org> | 2012-01-25 00:22:53 +0000 |
---|---|---|
committer | rmacklem <rmacklem@FreeBSD.org> | 2012-01-25 00:22:53 +0000 |
commit | 911de305602ff6d54ef262ead117c4a828f3e340 (patch) | |
tree | c530b4124fc83044c9646391fafc6de00b247fc5 /sys | |
parent | 538ff2e745ffc35d0f24d19ebc0315160097b97f (diff) | |
download | FreeBSD-src-911de305602ff6d54ef262ead117c4a828f3e340.zip FreeBSD-src-911de305602ff6d54ef262ead117c4a828f3e340.tar.gz |
If a mount -u is done to either NFS client that switches it
from TCP to UDP and the rsize/wsize/readdirsize is greater
than NFS_MAXDGRAMDATA, it is possible for a thread doing an
I/O RPC to get stuck repeatedly doing retries. This happens
because the RPC will use a resize/wsize/readdirsize that won't
work for UDP and, as such, it will keep failing indefinitely.
This patch returns an error for this case, to avoid the problem.
A discussion on freebsd-fs@ seemed to indicate that returning
an error was preferable to silently ignoring the "udp"/"mntudp"
option.
This problem was discovered while investigating a problem reported
by pjd@ via email.
MFC after: 2 weeks
Diffstat (limited to 'sys')
-rw-r--r-- | sys/fs/nfsclient/nfs_clvfsops.c | 17 | ||||
-rw-r--r-- | sys/nfsclient/nfs_vfsops.c | 17 |
2 files changed, 34 insertions, 0 deletions
diff --git a/sys/fs/nfsclient/nfs_clvfsops.c b/sys/fs/nfsclient/nfs_clvfsops.c index ccb35f1..5ddfa27 100644 --- a/sys/fs/nfsclient/nfs_clvfsops.c +++ b/sys/fs/nfsclient/nfs_clvfsops.c @@ -989,6 +989,23 @@ nfs_mount(struct mount *mp) error = EIO; goto out; } + + /* + * Cannot switch to UDP if current rsize/wsize/readdirsize is + * too large, since there may be an I/O RPC in progress that + * will get retried after the switch to the UDP socket. These + * retries will fail over and over and over again. + */ + if (args.sotype == SOCK_DGRAM && + (nmp->nm_rsize > NFS_MAXDGRAMDATA || + nmp->nm_wsize > NFS_MAXDGRAMDATA || + nmp->nm_readdirsize > NFS_MAXDGRAMDATA)) { + vfs_mount_error(mp, + "old rsize/wsize/readdirsize greater than UDP max"); + error = EINVAL; + goto out; + } + /* * When doing an update, we can't change version, * security, switch lockd strategies or change cookie diff --git a/sys/nfsclient/nfs_vfsops.c b/sys/nfsclient/nfs_vfsops.c index fafc253..e43c048 100644 --- a/sys/nfsclient/nfs_vfsops.c +++ b/sys/nfsclient/nfs_vfsops.c @@ -1106,6 +1106,23 @@ nfs_mount(struct mount *mp) error = EIO; goto out; } + + /* + * Cannot switch to UDP if current rsize/wsize/readdirsize is + * too large, since there may be an I/O RPC in progress that + * will get retried after the switch to the UDP socket. These + * retries will fail over and over and over again. + */ + if (args.sotype == SOCK_DGRAM && + (nmp->nm_rsize > NFS_MAXDGRAMDATA || + nmp->nm_wsize > NFS_MAXDGRAMDATA || + nmp->nm_readdirsize > NFS_MAXDGRAMDATA)) { + vfs_mount_error(mp, + "old rsize/wsize/readdirsize greater than UDP max"); + error = EINVAL; + goto out; + } + /* * When doing an update, we can't change from or to * v3, switch lockd strategies or change cookie translation |