|
@@ -365,6 +365,24 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
|
|
|
*/
|
|
|
return 0;
|
|
|
|
|
|
+ if (file->f_version == 0) {
|
|
|
+ /*
|
|
|
+ * The file was seek'ed, which means that @file->private_data
|
|
|
+ * is now invalid. This may also be just the first
|
|
|
+ * 'ubifs_readdir()' invocation, in which case
|
|
|
+ * @file->private_data is NULL, and the below code is
|
|
|
+ * basically a no-op.
|
|
|
+ */
|
|
|
+ kfree(file->private_data);
|
|
|
+ file->private_data = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * 'generic_file_llseek()' unconditionally sets @file->f_version to
|
|
|
+ * zero, and we use this for detecting whether the file was seek'ed.
|
|
|
+ */
|
|
|
+ file->f_version = 1;
|
|
|
+
|
|
|
/* File positions 0 and 1 correspond to "." and ".." */
|
|
|
if (pos == 0) {
|
|
|
ubifs_assert(!file->private_data);
|
|
@@ -438,6 +456,14 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
|
|
|
file->f_pos = pos = key_hash_flash(c, &dent->key);
|
|
|
file->private_data = dent;
|
|
|
cond_resched();
|
|
|
+
|
|
|
+ if (file->f_version == 0)
|
|
|
+ /*
|
|
|
+ * The file was seek'ed meanwhile, lets return and start
|
|
|
+ * reading direntries from the new position on the next
|
|
|
+ * invocation.
|
|
|
+ */
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
out:
|
|
@@ -448,15 +474,13 @@ out:
|
|
|
|
|
|
kfree(file->private_data);
|
|
|
file->private_data = NULL;
|
|
|
+ /* 2 is a special value indicating that there are no more direntries */
|
|
|
file->f_pos = 2;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/* If a directory is seeked, we have to free saved readdir() state */
|
|
|
static loff_t ubifs_dir_llseek(struct file *file, loff_t offset, int whence)
|
|
|
{
|
|
|
- kfree(file->private_data);
|
|
|
- file->private_data = NULL;
|
|
|
return generic_file_llseek(file, offset, whence);
|
|
|
}
|
|
|
|