@@ -349,31 +349,50 @@ static unsigned int vfs_dent_type(uint8_t type)
349
349
static int ubifs_readdir (struct file * file , void * dirent , filldir_t filldir )
350
350
{
351
351
int err , over = 0 ;
352
+ loff_t pos = file -> f_pos ;
352
353
struct qstr nm ;
353
354
union ubifs_key key ;
354
355
struct ubifs_dent_node * dent ;
355
356
struct inode * dir = file_inode (file );
356
357
struct ubifs_info * c = dir -> i_sb -> s_fs_info ;
357
358
358
- dbg_gen ("dir ino %lu, f_pos %#llx" , dir -> i_ino , file -> f_pos );
359
+ dbg_gen ("dir ino %lu, f_pos %#llx" , dir -> i_ino , pos );
359
360
360
- if (file -> f_pos > UBIFS_S_KEY_HASH_MASK || file -> f_pos == 2 )
361
+ if (pos > UBIFS_S_KEY_HASH_MASK || pos == 2 )
361
362
/*
362
363
* The directory was seek'ed to a senseless position or there
363
364
* are no more entries.
364
365
*/
365
366
return 0 ;
366
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
+
367
386
/* File positions 0 and 1 correspond to "." and ".." */
368
- if (file -> f_pos == 0 ) {
387
+ if (pos == 0 ) {
369
388
ubifs_assert (!file -> private_data );
370
389
over = filldir (dirent , "." , 1 , 0 , dir -> i_ino , DT_DIR );
371
390
if (over )
372
391
return 0 ;
373
- file -> f_pos = 1 ;
392
+ file -> f_pos = pos = 1 ;
374
393
}
375
394
376
- if (file -> f_pos == 1 ) {
395
+ if (pos == 1 ) {
377
396
ubifs_assert (!file -> private_data );
378
397
over = filldir (dirent , ".." , 2 , 1 ,
379
398
parent_ino (file -> f_path .dentry ), DT_DIR );
@@ -389,25 +408,24 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
389
408
goto out ;
390
409
}
391
410
392
- file -> f_pos = key_hash_flash (c , & dent -> key );
411
+ file -> f_pos = pos = key_hash_flash (c , & dent -> key );
393
412
file -> private_data = dent ;
394
413
}
395
414
396
415
dent = file -> private_data ;
397
416
if (!dent ) {
398
417
/*
399
418
* The directory was seek'ed to and is now readdir'ed.
400
- * Find the entry corresponding to @file->f_pos or the
401
- * closest one.
419
+ * Find the entry corresponding to @pos or the closest one.
402
420
*/
403
- dent_key_init_hash (c , & key , dir -> i_ino , file -> f_pos );
421
+ dent_key_init_hash (c , & key , dir -> i_ino , pos );
404
422
nm .name = NULL ;
405
423
dent = ubifs_tnc_next_ent (c , & key , & nm );
406
424
if (IS_ERR (dent )) {
407
425
err = PTR_ERR (dent );
408
426
goto out ;
409
427
}
410
- file -> f_pos = key_hash_flash (c , & dent -> key );
428
+ file -> f_pos = pos = key_hash_flash (c , & dent -> key );
411
429
file -> private_data = dent ;
412
430
}
413
431
@@ -419,7 +437,7 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
419
437
ubifs_inode (dir )-> creat_sqnum );
420
438
421
439
nm .len = le16_to_cpu (dent -> nlen );
422
- over = filldir (dirent , dent -> name , nm .len , file -> f_pos ,
440
+ over = filldir (dirent , dent -> name , nm .len , pos ,
423
441
le64_to_cpu (dent -> inum ),
424
442
vfs_dent_type (dent -> type ));
425
443
if (over )
@@ -435,9 +453,17 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
435
453
}
436
454
437
455
kfree (file -> private_data );
438
- file -> f_pos = key_hash_flash (c , & dent -> key );
456
+ file -> f_pos = pos = key_hash_flash (c , & dent -> key );
439
457
file -> private_data = dent ;
440
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
469
out :
@@ -448,15 +474,13 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
448
474
449
475
kfree (file -> private_data );
450
476
file -> private_data = NULL ;
477
+ /* 2 is a special value indicating that there are no more direntries */
451
478
file -> f_pos = 2 ;
452
479
return 0 ;
453
480
}
454
481
455
- /* If a directory is seeked, we have to free saved readdir() state */
456
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
484
return generic_file_llseek (file , offset , whence );
461
485
}
462
486
0 commit comments