@@ -294,6 +294,7 @@ int simple_offset_add(struct offset_ctx *octx, struct dentry *dentry)
return ret;
offset_set(dentry, offset);
+ WRITE_ONCE(dentry->d_time, jiffies);
return 0;
}
@@ -454,9 +455,7 @@ void simple_offset_destroy(struct offset_ctx *octx)
static int offset_dir_open(struct inode *inode, struct file *file)
{
- struct offset_ctx *ctx = inode->i_op->get_offset_ctx(inode);
-
- file->private_data = (void *)ctx->next_offset;
+ file->private_data = (void *)jiffies;
return 0;
}
@@ -473,9 +472,6 @@ static int offset_dir_open(struct inode *inode, struct file *file)
*/
static loff_t offset_dir_llseek(struct file *file, loff_t offset, int whence)
{
- struct inode *inode = file->f_inode;
- struct offset_ctx *ctx = inode->i_op->get_offset_ctx(inode);
-
switch (whence) {
case SEEK_CUR:
offset += file->f_pos;
@@ -490,7 +486,8 @@ static loff_t offset_dir_llseek(struct file *file, loff_t offset, int whence)
/* In this case, ->private_data is protected by f_pos_lock */
if (!offset)
- file->private_data = (void *)ctx->next_offset;
+ /* Make newer child entries visible */
+ file->private_data = (void *)jiffies;
return vfs_setpos(file, offset, LONG_MAX);
}
@@ -521,7 +518,8 @@ static bool offset_dir_emit(struct dir_context *ctx, struct dentry *dentry)
inode->i_ino, fs_umode_to_dtype(inode->i_mode));
}
-static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx, long last_index)
+static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx,
+ unsigned long fence)
{
struct offset_ctx *octx = inode->i_op->get_offset_ctx(inode);
struct dentry *dentry;
@@ -531,14 +529,15 @@ static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx, lon
if (!dentry)
return;
- if (dentry2offset(dentry) >= last_index) {
- dput(dentry);
- return;
- }
-
- if (!offset_dir_emit(ctx, dentry)) {
- dput(dentry);
- return;
+ /*
+ * Output only child entries created during or before
+ * the current opendir epoch.
+ */
+ if (time_before_eq(dentry->d_time, fence)) {
+ if (!offset_dir_emit(ctx, dentry)) {
+ dput(dentry);
+ return;
+ }
}
ctx->pos = dentry2offset(dentry) + 1;
@@ -569,15 +568,14 @@ static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx, lon
*/
static int offset_readdir(struct file *file, struct dir_context *ctx)
{
+ unsigned long fence = (unsigned long)file->private_data;
struct dentry *dir = file->f_path.dentry;
- long last_index = (long)file->private_data;
lockdep_assert_held(&d_inode(dir)->i_rwsem);
if (!dir_emit_dots(file, ctx))
return 0;
-
- offset_iterate_dir(d_inode(dir), ctx, last_index);
+ offset_iterate_dir(d_inode(dir), ctx, fence);
return 0;
}