diff options
| -rw-r--r-- | fs/ubifs/dir.c | 30 |
1 files changed, 27 insertions, 3 deletions
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index 8e587afd7732..605af512aec2 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c | |||
| @@ -365,6 +365,24 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir) | |||
| 365 | */ | 365 | */ |
| 366 | return 0; | 366 | return 0; |
| 367 | 367 | ||
| 368 | if (file->f_version == 0) { | ||
| 369 | /* | ||
| 370 | * The file was seek'ed, which means that @file->private_data | ||
| 371 | * is now invalid. This may also be just the first | ||
| 372 | * 'ubifs_readdir()' invocation, in which case | ||
| 373 | * @file->private_data is NULL, and the below code is | ||
| 374 | * basically a no-op. | ||
| 375 | */ | ||
| 376 | kfree(file->private_data); | ||
| 377 | file->private_data = NULL; | ||
| 378 | } | ||
| 379 | |||
| 380 | /* | ||
| 381 | * 'generic_file_llseek()' unconditionally sets @file->f_version to | ||
| 382 | * zero, and we use this for detecting whether the file was seek'ed. | ||
| 383 | */ | ||
| 384 | file->f_version = 1; | ||
| 385 | |||
| 368 | /* File positions 0 and 1 correspond to "." and ".." */ | 386 | /* File positions 0 and 1 correspond to "." and ".." */ |
| 369 | if (pos == 0) { | 387 | if (pos == 0) { |
| 370 | ubifs_assert(!file->private_data); | 388 | ubifs_assert(!file->private_data); |
| @@ -438,6 +456,14 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir) | |||
| 438 | file->f_pos = pos = key_hash_flash(c, &dent->key); | 456 | file->f_pos = pos = key_hash_flash(c, &dent->key); |
| 439 | file->private_data = dent; | 457 | file->private_data = dent; |
| 440 | cond_resched(); | 458 | cond_resched(); |
| 459 | |||
| 460 | if (file->f_version == 0) | ||
| 461 | /* | ||
| 462 | * The file was seek'ed meanwhile, lets return and start | ||
| 463 | * reading direntries from the new position on the next | ||
| 464 | * invocation. | ||
| 465 | */ | ||
| 466 | return 0; | ||
| 441 | } | 467 | } |
| 442 | 468 | ||
| 443 | out: | 469 | out: |
| @@ -448,15 +474,13 @@ out: | |||
| 448 | 474 | ||
| 449 | kfree(file->private_data); | 475 | kfree(file->private_data); |
| 450 | file->private_data = NULL; | 476 | file->private_data = NULL; |
| 477 | /* 2 is a special value indicating that there are no more direntries */ | ||
| 451 | file->f_pos = 2; | 478 | file->f_pos = 2; |
| 452 | return 0; | 479 | return 0; |
| 453 | } | 480 | } |
| 454 | 481 | ||
| 455 | /* If a directory is seeked, we have to free saved readdir() state */ | ||
| 456 | static loff_t ubifs_dir_llseek(struct file *file, loff_t offset, int whence) | 482 | static loff_t ubifs_dir_llseek(struct file *file, loff_t offset, int whence) |
| 457 | { | 483 | { |
| 458 | kfree(file->private_data); | ||
| 459 | file->private_data = NULL; | ||
| 460 | return generic_file_llseek(file, offset, whence); | 484 | return generic_file_llseek(file, offset, whence); |
| 461 | } | 485 | } |
| 462 | 486 | ||
