aboutsummaryrefslogtreecommitdiffstats
path: root/fs/orangefs
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2016-02-16 19:54:13 -0500
committerMike Marshall <hubcap@omnibond.com>2016-03-25 22:30:54 -0400
commit9f5e2f7f1b4bf7d0b19d88edd9425510fadbb9e4 (patch)
tree7c0ac500aa53497534eed471e7889c149876f2c5 /fs/orangefs
parentfecd86aac5a7621635b61e7491f0ed73610d76fa (diff)
orangefs: get rid of readdir_handle_s
no point, really - we couldn't keep those across the calls of getdents(); it would be too easy to DoS, having all slots exhausted. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Mike Marshall <hubcap@omnibond.com>
Diffstat (limited to 'fs/orangefs')
-rw-r--r--fs/orangefs/dir.c93
1 files changed, 30 insertions, 63 deletions
diff --git a/fs/orangefs/dir.c b/fs/orangefs/dir.c
index 259b667f6c8f..53a411732606 100644
--- a/fs/orangefs/dir.c
+++ b/fs/orangefs/dir.c
@@ -8,11 +8,6 @@
8#include "orangefs-kernel.h" 8#include "orangefs-kernel.h"
9#include "orangefs-bufmap.h" 9#include "orangefs-bufmap.h"
10 10
11struct readdir_handle_s {
12 struct orangefs_readdir_response_s readdir_response;
13 void *dents_buf;
14};
15
16/* 11/*
17 * decode routine used by kmod to deal with the blob sent from 12 * decode routine used by kmod to deal with the blob sent from
18 * userspace for readdirs. The blob contains zero or more of these 13 * userspace for readdirs. The blob contains zero or more of these
@@ -141,44 +136,6 @@ out:
141 return ret; 136 return ret;
142} 137}
143 138
144static long readdir_handle_ctor(struct readdir_handle_s *rhandle, void *buf,
145 size_t size)
146{
147 long ret;
148
149 if (buf == NULL) {
150 gossip_err
151 ("Invalid NULL buffer specified in readdir_handle_ctor\n");
152 return -ENOMEM;
153 }
154 rhandle->dents_buf = buf;
155 ret = decode_dirents(buf, size, &rhandle->readdir_response);
156 if (ret < 0) {
157 gossip_err("Could not decode readdir from buffer %ld\n", ret);
158 gossip_debug(GOSSIP_DIR_DEBUG, "vfree %p\n", buf);
159 vfree(buf);
160 rhandle->dents_buf = NULL;
161 }
162 return ret;
163}
164
165static void readdir_handle_dtor(struct readdir_handle_s *rhandle)
166{
167 if (rhandle == NULL)
168 return;
169
170 /* kfree(NULL) is safe */
171 kfree(rhandle->readdir_response.dirent_array);
172 rhandle->readdir_response.dirent_array = NULL;
173
174 if (rhandle->dents_buf) {
175 gossip_debug(GOSSIP_DIR_DEBUG, "vfree %p\n",
176 rhandle->dents_buf);
177 vfree(rhandle->dents_buf);
178 rhandle->dents_buf = NULL;
179 }
180}
181
182/* 139/*
183 * Read directory entries from an instance of an open directory. 140 * Read directory entries from an instance of an open directory.
184 */ 141 */
@@ -198,7 +155,8 @@ static int orangefs_readdir(struct file *file, struct dir_context *ctx)
198 struct orangefs_kernel_op_s *new_op = NULL; 155 struct orangefs_kernel_op_s *new_op = NULL;
199 struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(dentry->d_inode); 156 struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(dentry->d_inode);
200 int buffer_full = 0; 157 int buffer_full = 0;
201 struct readdir_handle_s rhandle; 158 struct orangefs_readdir_response_s readdir_response;
159 void *dents_buf;
202 int i = 0; 160 int i = 0;
203 int len = 0; 161 int len = 0;
204 ino_t current_ino = 0; 162 ino_t current_ino = 0;
@@ -224,8 +182,7 @@ static int orangefs_readdir(struct file *file, struct dir_context *ctx)
224 "orangefs_readdir called on %s (pos=%llu)\n", 182 "orangefs_readdir called on %s (pos=%llu)\n",
225 dentry->d_name.name, llu(pos)); 183 dentry->d_name.name, llu(pos));
226 184
227 rhandle.dents_buf = NULL; 185 memset(&readdir_response, 0, sizeof(readdir_response));
228 memset(&rhandle.readdir_response, 0, sizeof(rhandle.readdir_response));
229 186
230 new_op = op_alloc(ORANGEFS_VFS_OP_READDIR); 187 new_op = op_alloc(ORANGEFS_VFS_OP_READDIR);
231 if (!new_op) 188 if (!new_op)
@@ -278,7 +235,7 @@ get_new_buffer_index:
278 if (ret == -EIO && op_state_purged(new_op)) { 235 if (ret == -EIO && op_state_purged(new_op)) {
279 gossip_err("%s: Client is down. Aborting readdir call.\n", 236 gossip_err("%s: Client is down. Aborting readdir call.\n",
280 __func__); 237 __func__);
281 goto out_free_op; 238 goto out_slot;
282 } 239 }
283 240
284 if (ret < 0 || new_op->downcall.status != 0) { 241 if (ret < 0 || new_op->downcall.status != 0) {
@@ -287,18 +244,22 @@ get_new_buffer_index:
287 new_op->downcall.status); 244 new_op->downcall.status);
288 if (ret >= 0) 245 if (ret >= 0)
289 ret = new_op->downcall.status; 246 ret = new_op->downcall.status;
290 goto out_free_op; 247 goto out_slot;
248 }
249
250 dents_buf = new_op->downcall.trailer_buf;
251 if (dents_buf == NULL) {
252 gossip_err("Invalid NULL buffer in readdir response\n");
253 ret = -ENOMEM;
254 goto out_slot;
291 } 255 }
292 256
293 bytes_decoded = 257 bytes_decoded = decode_dirents(dents_buf, new_op->downcall.trailer_size,
294 readdir_handle_ctor(&rhandle, 258 &readdir_response);
295 new_op->downcall.trailer_buf,
296 new_op->downcall.trailer_size);
297 if (bytes_decoded < 0) { 259 if (bytes_decoded < 0) {
298 gossip_err("orangefs_readdir: Could not decode trailer buffer into a readdir response %d\n",
299 ret);
300 ret = bytes_decoded; 260 ret = bytes_decoded;
301 goto out_free_op; 261 gossip_err("Could not decode readdir from buffer %d\n", ret);
262 goto out_vfree;
302 } 263 }
303 264
304 if (bytes_decoded != new_op->downcall.trailer_size) { 265 if (bytes_decoded != new_op->downcall.trailer_size) {
@@ -345,14 +306,14 @@ get_new_buffer_index:
345 gossip_debug(GOSSIP_DIR_DEBUG, 306 gossip_debug(GOSSIP_DIR_DEBUG,
346 "%s: dirent_outcount:%d:\n", 307 "%s: dirent_outcount:%d:\n",
347 __func__, 308 __func__,
348 rhandle.readdir_response.orangefs_dirent_outcount); 309 readdir_response.orangefs_dirent_outcount);
349 for (i = ctx->pos; 310 for (i = ctx->pos;
350 i < rhandle.readdir_response.orangefs_dirent_outcount; 311 i < readdir_response.orangefs_dirent_outcount;
351 i++) { 312 i++) {
352 len = rhandle.readdir_response.dirent_array[i].d_length; 313 len = readdir_response.dirent_array[i].d_length;
353 current_entry = rhandle.readdir_response.dirent_array[i].d_name; 314 current_entry = readdir_response.dirent_array[i].d_name;
354 current_ino = orangefs_khandle_to_ino( 315 current_ino = orangefs_khandle_to_ino(
355 &(rhandle.readdir_response.dirent_array[i].khandle)); 316 &readdir_response.dirent_array[i].khandle);
356 317
357 gossip_debug(GOSSIP_DIR_DEBUG, 318 gossip_debug(GOSSIP_DIR_DEBUG,
358 "calling dir_emit for %s with len %d" 319 "calling dir_emit for %s with len %d"
@@ -382,14 +343,14 @@ get_new_buffer_index:
382 * getting another batch... 343 * getting another batch...
383 */ 344 */
384 if (ret) { 345 if (ret) {
385 *ptoken = rhandle.readdir_response.token; 346 *ptoken = readdir_response.token;
386 ctx->pos = ORANGEFS_ITERATE_NEXT; 347 ctx->pos = ORANGEFS_ITERATE_NEXT;
387 } 348 }
388 349
389 /* 350 /*
390 * Did we hit the end of the directory? 351 * Did we hit the end of the directory?
391 */ 352 */
392 if (rhandle.readdir_response.token == ORANGEFS_READDIR_END && 353 if (readdir_response.token == ORANGEFS_READDIR_END &&
393 !buffer_full) { 354 !buffer_full) {
394 gossip_debug(GOSSIP_DIR_DEBUG, 355 gossip_debug(GOSSIP_DIR_DEBUG,
395 "End of dir detected; setting ctx->pos to ORANGEFS_READDIR_END.\n"); 356 "End of dir detected; setting ctx->pos to ORANGEFS_READDIR_END.\n");
@@ -397,7 +358,13 @@ get_new_buffer_index:
397 } 358 }
398 359
399out_destroy_handle: 360out_destroy_handle:
400 readdir_handle_dtor(&rhandle); 361 /* kfree(NULL) is safe */
362 kfree(readdir_response.dirent_array);
363out_vfree:
364 gossip_debug(GOSSIP_DIR_DEBUG, "vfree %p\n", dents_buf);
365 vfree(dents_buf);
366out_slot:
367 orangefs_readdir_index_put(buffer_index);
401out_free_op: 368out_free_op:
402 op_release(new_op); 369 op_release(new_op);
403 gossip_debug(GOSSIP_DIR_DEBUG, "orangefs_readdir returning %d\n", ret); 370 gossip_debug(GOSSIP_DIR_DEBUG, "orangefs_readdir returning %d\n", ret);