Commit c2f1a551dea8b37c2e0cb886885c250fb703e9d8
Committed by
Linus Torvalds
1 parent
1e5140279f
Exists in
master
and in
7 other branches
knfsd: nfsd4: vary maximum delegation limit based on RAM size
Our original NFSv4 delegation policy was to give out a read delegation on any open when it was possible to. Since the lifetime of a delegation isn't limited to that of an open, a client may quite reasonably hang on to a delegation as long as it has the inode cached. This becomes an obvious problem the first time a client's inode cache approaches the size of the server's total memory. Our first quick solution was to add a hard-coded limit. This patch makes a mild incremental improvement by varying that limit according to the server's total memory size, allowing at most 4 delegations per megabyte of RAM. My quick back-of-the-envelope calculation finds that in the worst case (where every delegation is for a different inode), a delegation could take about 1.5K, which would make the worst case usage about 6% of memory. The new limit works out to be about the same as the old on a 1-gig server. [akpm@linux-foundation.org: Don't needlessly bloat vmlinux] [akpm@linux-foundation.org: Make it right for highmem machines] Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu> Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 3 changed files with 27 additions and 1 deletions Side-by-side Diff
fs/nfsd/nfs4state.c
... | ... | @@ -49,6 +49,7 @@ |
49 | 49 | #include <linux/nfsd/state.h> |
50 | 50 | #include <linux/nfsd/xdr4.h> |
51 | 51 | #include <linux/namei.h> |
52 | +#include <linux/swap.h> | |
52 | 53 | #include <linux/mutex.h> |
53 | 54 | #include <linux/lockd/bind.h> |
54 | 55 | #include <linux/module.h> |
... | ... | @@ -150,6 +151,7 @@ |
150 | 151 | } |
151 | 152 | |
152 | 153 | static int num_delegations; |
154 | +unsigned int max_delegations; | |
153 | 155 | |
154 | 156 | /* |
155 | 157 | * Open owner state (share locks) |
... | ... | @@ -193,7 +195,7 @@ |
193 | 195 | struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback; |
194 | 196 | |
195 | 197 | dprintk("NFSD alloc_init_deleg\n"); |
196 | - if (num_delegations > STATEID_HASH_SIZE * 4) | |
198 | + if (num_delegations > max_delegations) | |
197 | 199 | return NULL; |
198 | 200 | dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL); |
199 | 201 | if (dp == NULL) |
... | ... | @@ -3197,6 +3199,27 @@ |
3197 | 3199 | return max(user_lease_time, lease_time) * HZ; |
3198 | 3200 | } |
3199 | 3201 | |
3202 | +/* | |
3203 | + * Since the lifetime of a delegation isn't limited to that of an open, a | |
3204 | + * client may quite reasonably hang on to a delegation as long as it has | |
3205 | + * the inode cached. This becomes an obvious problem the first time a | |
3206 | + * client's inode cache approaches the size of the server's total memory. | |
3207 | + * | |
3208 | + * For now we avoid this problem by imposing a hard limit on the number | |
3209 | + * of delegations, which varies according to the server's memory size. | |
3210 | + */ | |
3211 | +static void | |
3212 | +set_max_delegations(void) | |
3213 | +{ | |
3214 | + /* | |
3215 | + * Allow at most 4 delegations per megabyte of RAM. Quick | |
3216 | + * estimates suggest that in the worst case (where every delegation | |
3217 | + * is for a different inode), a delegation could take about 1.5K, | |
3218 | + * giving a worst case usage of about 6% of memory. | |
3219 | + */ | |
3220 | + max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); | |
3221 | +} | |
3222 | + | |
3200 | 3223 | /* initialization to perform when the nfsd service is started: */ |
3201 | 3224 | |
3202 | 3225 | static void |
... | ... | @@ -3212,6 +3235,7 @@ |
3212 | 3235 | grace_time/HZ); |
3213 | 3236 | laundry_wq = create_singlethread_workqueue("nfsd4"); |
3214 | 3237 | queue_delayed_work(laundry_wq, &laundromat_work, grace_time); |
3238 | + set_max_delegations(); | |
3215 | 3239 | } |
3216 | 3240 | |
3217 | 3241 | int |
include/linux/nfsd/nfsd.h