diff options
author | NeilBrown <neilb@suse.de> | 2006-04-11 01:55:41 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-04-11 09:18:53 -0400 |
commit | ef0f3390ebedac78bff1936bbb26606bca83e891 (patch) | |
tree | 86fceb6260a80b9d3ba41b13371b2be73198c300 /fs | |
parent | 4e2fd495b520b51e4ba83340f13520b7f07e3743 (diff) |
[PATCH] knfsd: nfsd4: limit number of delegations handed out.
It's very easy for the server to DOS itself by just giving out too many
delegations.
For now we just solve the problem with a dumb hard limit. Eventually we'll
want a smarter policy.
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfsd/nfs4state.c | 74 |
1 files changed, 40 insertions, 34 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index e97c58aafde5..1e2a89aaf895 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -147,6 +147,42 @@ get_nfs4_file(struct nfs4_file *fi) | |||
147 | kref_get(&fi->fi_ref); | 147 | kref_get(&fi->fi_ref); |
148 | } | 148 | } |
149 | 149 | ||
150 | static int num_delegations; | ||
151 | |||
152 | /* | ||
153 | * Open owner state (share locks) | ||
154 | */ | ||
155 | |||
156 | /* hash tables for nfs4_stateowner */ | ||
157 | #define OWNER_HASH_BITS 8 | ||
158 | #define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS) | ||
159 | #define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1) | ||
160 | |||
161 | #define ownerid_hashval(id) \ | ||
162 | ((id) & OWNER_HASH_MASK) | ||
163 | #define ownerstr_hashval(clientid, ownername) \ | ||
164 | (((clientid) + opaque_hashval((ownername.data), (ownername.len))) & OWNER_HASH_MASK) | ||
165 | |||
166 | static struct list_head ownerid_hashtbl[OWNER_HASH_SIZE]; | ||
167 | static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE]; | ||
168 | |||
169 | /* hash table for nfs4_file */ | ||
170 | #define FILE_HASH_BITS 8 | ||
171 | #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) | ||
172 | #define FILE_HASH_MASK (FILE_HASH_SIZE - 1) | ||
173 | /* hash table for (open)nfs4_stateid */ | ||
174 | #define STATEID_HASH_BITS 10 | ||
175 | #define STATEID_HASH_SIZE (1 << STATEID_HASH_BITS) | ||
176 | #define STATEID_HASH_MASK (STATEID_HASH_SIZE - 1) | ||
177 | |||
178 | #define file_hashval(x) \ | ||
179 | hash_ptr(x, FILE_HASH_BITS) | ||
180 | #define stateid_hashval(owner_id, file_id) \ | ||
181 | (((owner_id) + (file_id)) & STATEID_HASH_MASK) | ||
182 | |||
183 | static struct list_head file_hashtbl[FILE_HASH_SIZE]; | ||
184 | static struct list_head stateid_hashtbl[STATEID_HASH_SIZE]; | ||
185 | |||
150 | static struct nfs4_delegation * | 186 | static struct nfs4_delegation * |
151 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) | 187 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) |
152 | { | 188 | { |
@@ -155,9 +191,12 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
155 | struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback; | 191 | struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback; |
156 | 192 | ||
157 | dprintk("NFSD alloc_init_deleg\n"); | 193 | dprintk("NFSD alloc_init_deleg\n"); |
194 | if (num_delegations > STATEID_HASH_SIZE * 4) | ||
195 | return NULL; | ||
158 | dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL); | 196 | dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL); |
159 | if (dp == NULL) | 197 | if (dp == NULL) |
160 | return dp; | 198 | return dp; |
199 | num_delegations++; | ||
161 | INIT_LIST_HEAD(&dp->dl_perfile); | 200 | INIT_LIST_HEAD(&dp->dl_perfile); |
162 | INIT_LIST_HEAD(&dp->dl_perclnt); | 201 | INIT_LIST_HEAD(&dp->dl_perclnt); |
163 | INIT_LIST_HEAD(&dp->dl_recall_lru); | 202 | INIT_LIST_HEAD(&dp->dl_recall_lru); |
@@ -192,6 +231,7 @@ nfs4_put_delegation(struct nfs4_delegation *dp) | |||
192 | dprintk("NFSD: freeing dp %p\n",dp); | 231 | dprintk("NFSD: freeing dp %p\n",dp); |
193 | put_nfs4_file(dp->dl_file); | 232 | put_nfs4_file(dp->dl_file); |
194 | kmem_cache_free(deleg_slab, dp); | 233 | kmem_cache_free(deleg_slab, dp); |
234 | num_delegations--; | ||
195 | } | 235 | } |
196 | } | 236 | } |
197 | 237 | ||
@@ -943,40 +983,6 @@ out: | |||
943 | return status; | 983 | return status; |
944 | } | 984 | } |
945 | 985 | ||
946 | /* | ||
947 | * Open owner state (share locks) | ||
948 | */ | ||
949 | |||
950 | /* hash tables for nfs4_stateowner */ | ||
951 | #define OWNER_HASH_BITS 8 | ||
952 | #define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS) | ||
953 | #define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1) | ||
954 | |||
955 | #define ownerid_hashval(id) \ | ||
956 | ((id) & OWNER_HASH_MASK) | ||
957 | #define ownerstr_hashval(clientid, ownername) \ | ||
958 | (((clientid) + opaque_hashval((ownername.data), (ownername.len))) & OWNER_HASH_MASK) | ||
959 | |||
960 | static struct list_head ownerid_hashtbl[OWNER_HASH_SIZE]; | ||
961 | static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE]; | ||
962 | |||
963 | /* hash table for nfs4_file */ | ||
964 | #define FILE_HASH_BITS 8 | ||
965 | #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) | ||
966 | #define FILE_HASH_MASK (FILE_HASH_SIZE - 1) | ||
967 | /* hash table for (open)nfs4_stateid */ | ||
968 | #define STATEID_HASH_BITS 10 | ||
969 | #define STATEID_HASH_SIZE (1 << STATEID_HASH_BITS) | ||
970 | #define STATEID_HASH_MASK (STATEID_HASH_SIZE - 1) | ||
971 | |||
972 | #define file_hashval(x) \ | ||
973 | hash_ptr(x, FILE_HASH_BITS) | ||
974 | #define stateid_hashval(owner_id, file_id) \ | ||
975 | (((owner_id) + (file_id)) & STATEID_HASH_MASK) | ||
976 | |||
977 | static struct list_head file_hashtbl[FILE_HASH_SIZE]; | ||
978 | static struct list_head stateid_hashtbl[STATEID_HASH_SIZE]; | ||
979 | |||
980 | /* OPEN Share state helper functions */ | 986 | /* OPEN Share state helper functions */ |
981 | static inline struct nfs4_file * | 987 | static inline struct nfs4_file * |
982 | alloc_init_file(struct inode *ino) | 988 | alloc_init_file(struct inode *ino) |