summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2019-09-20 02:33:16 -0400
committerJ. Bruce Fields <bfields@redhat.com>2019-09-20 12:30:02 -0400
commit7f49fd5d7acd82163685559045d04d49433581cc (patch)
treef58fc0bd9c69bf4ebea13bc820ec626eaa2dcc07
parent6ee95d1c899186c0798cafd25998d436bcdb9618 (diff)
nfsd: handle drc over-allocation gracefully.
Currently, if there are more clients than allowed for by the space allocation in set_max_drc(), we fail a SESSION_CREATE request with NFS4ERR_DELAY. This means that the client retries indefinitely, which isn't a user-friendly response. The RFC requires NFS4ERR_NOSPC, but that would at best result in a clean failure on the client, which is not much more friendly. The current space allocation is a best-guess and doesn't provide any guarantees, we could still run out of space when trying to allocate drc space. So fail more gracefully - always give out at least one slot. If all clients used all the space in all slots, we might start getting memory pressure, but that is possible anyway. So ensure 'num' is always at least 1, and remove the test for it being zero. Signed-off-by: NeilBrown <neilb@suse.de> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r--fs/nfsd/nfs4state.c19
1 files changed, 15 insertions, 4 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index da1093dd5016..8622d6dd45c0 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1575,14 +1575,25 @@ static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca)
1575 unsigned long avail, total_avail; 1575 unsigned long avail, total_avail;
1576 1576
1577 spin_lock(&nfsd_drc_lock); 1577 spin_lock(&nfsd_drc_lock);
1578 total_avail = nfsd_drc_max_mem - nfsd_drc_mem_used; 1578 if (nfsd_drc_max_mem > nfsd_drc_mem_used)
1579 total_avail = nfsd_drc_max_mem - nfsd_drc_mem_used;
1580 else
1581 /* We have handed out more space than we chose in
1582 * set_max_drc() to allow. That isn't really a
1583 * problem as long as that doesn't make us think we
1584 * have lots more due to integer overflow.
1585 */
1586 total_avail = 0;
1579 avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, total_avail); 1587 avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, total_avail);
1580 /* 1588 /*
1581 * Never use more than a third of the remaining memory, 1589 * Never use more than a third of the remaining memory,
1582 * unless it's the only way to give this client a slot: 1590 * unless it's the only way to give this client a slot.
1591 * Give the client one slot even if that would require
1592 * over-allocation--it is better than failure.
1583 */ 1593 */
1584 avail = clamp_t(unsigned long, avail, slotsize, total_avail/3); 1594 avail = clamp_t(unsigned long, avail, slotsize, total_avail/3);
1585 num = min_t(int, num, avail / slotsize); 1595 num = min_t(int, num, avail / slotsize);
1596 num = max_t(int, num, 1);
1586 nfsd_drc_mem_used += num * slotsize; 1597 nfsd_drc_mem_used += num * slotsize;
1587 spin_unlock(&nfsd_drc_lock); 1598 spin_unlock(&nfsd_drc_lock);
1588 1599
@@ -3174,10 +3185,10 @@ static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfs
3174 * performance. When short on memory we therefore prefer to 3185 * performance. When short on memory we therefore prefer to
3175 * decrease number of slots instead of their size. Clients that 3186 * decrease number of slots instead of their size. Clients that
3176 * request larger slots than they need will get poor results: 3187 * request larger slots than they need will get poor results:
3188 * Note that we always allow at least one slot, because our
3189 * accounting is soft and provides no guarantees either way.
3177 */ 3190 */
3178 ca->maxreqs = nfsd4_get_drc_mem(ca); 3191 ca->maxreqs = nfsd4_get_drc_mem(ca);
3179 if (!ca->maxreqs)
3180 return nfserr_jukebox;
3181 3192
3182 return nfs_ok; 3193 return nfs_ok;
3183} 3194}