13
13
#include <linux/pagemap.h>
14
14
#include <linux/ucs2_string.h>
15
15
#include <linux/slab.h>
16
+ #include <linux/suspend.h>
16
17
#include <linux/magic.h>
17
18
#include <linux/statfs.h>
18
19
#include <linux/notifier.h>
@@ -366,7 +367,7 @@ static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc)
366
367
if (err )
367
368
return err ;
368
369
369
- return efivar_init (efivarfs_callback , sb );
370
+ return efivar_init (efivarfs_callback , sb , true );
370
371
}
371
372
372
373
static int efivarfs_get_tree (struct fs_context * fc )
@@ -390,6 +391,148 @@ static const struct fs_context_operations efivarfs_context_ops = {
390
391
.reconfigure = efivarfs_reconfigure ,
391
392
};
392
393
394
+ struct efivarfs_ctx {
395
+ struct dir_context ctx ;
396
+ struct super_block * sb ;
397
+ struct dentry * dentry ;
398
+ };
399
+
400
+ static bool efivarfs_actor (struct dir_context * ctx , const char * name , int len ,
401
+ loff_t offset , u64 ino , unsigned mode )
402
+ {
403
+ unsigned long size ;
404
+ struct efivarfs_ctx * ectx = container_of (ctx , struct efivarfs_ctx , ctx );
405
+ struct qstr qstr = { .name = name , .len = len };
406
+ struct dentry * dentry = d_hash_and_lookup (ectx -> sb -> s_root , & qstr );
407
+ struct inode * inode ;
408
+ struct efivar_entry * entry ;
409
+ int err ;
410
+
411
+ if (IS_ERR_OR_NULL (dentry ))
412
+ return true;
413
+
414
+ inode = d_inode (dentry );
415
+ entry = efivar_entry (inode );
416
+
417
+ err = efivar_entry_size (entry , & size );
418
+ size += sizeof (__u32 ); /* attributes */
419
+ if (err )
420
+ size = 0 ;
421
+
422
+ inode_lock (inode );
423
+ i_size_write (inode , size );
424
+ inode_unlock (inode );
425
+
426
+ if (!size ) {
427
+ ectx -> dentry = dentry ;
428
+ return false;
429
+ }
430
+
431
+ dput (dentry );
432
+
433
+ return true;
434
+ }
435
+
436
+ static int efivarfs_check_missing (efi_char16_t * name16 , efi_guid_t vendor ,
437
+ unsigned long name_size , void * data )
438
+ {
439
+ char * name ;
440
+ struct super_block * sb = data ;
441
+ struct dentry * dentry ;
442
+ struct qstr qstr ;
443
+ int err ;
444
+
445
+ if (guid_equal (& vendor , & LINUX_EFI_RANDOM_SEED_TABLE_GUID ))
446
+ return 0 ;
447
+
448
+ name = efivar_get_utf8name (name16 , & vendor );
449
+ if (!name )
450
+ return - ENOMEM ;
451
+
452
+ qstr .name = name ;
453
+ qstr .len = strlen (name );
454
+ dentry = d_hash_and_lookup (sb -> s_root , & qstr );
455
+ if (IS_ERR (dentry )) {
456
+ err = PTR_ERR (dentry );
457
+ goto out ;
458
+ }
459
+
460
+ if (!dentry ) {
461
+ /* found missing entry */
462
+ pr_info ("efivarfs: creating variable %s\n" , name );
463
+ return efivarfs_create_dentry (sb , name16 , name_size , vendor , name );
464
+ }
465
+
466
+ dput (dentry );
467
+ err = 0 ;
468
+
469
+ out :
470
+ kfree (name );
471
+
472
+ return err ;
473
+ }
474
+
475
+ static int efivarfs_pm_notify (struct notifier_block * nb , unsigned long action ,
476
+ void * ptr )
477
+ {
478
+ struct efivarfs_fs_info * sfi = container_of (nb , struct efivarfs_fs_info ,
479
+ pm_nb );
480
+ struct path path = { .mnt = NULL , .dentry = sfi -> sb -> s_root , };
481
+ struct efivarfs_ctx ectx = {
482
+ .ctx = {
483
+ .actor = efivarfs_actor ,
484
+ },
485
+ .sb = sfi -> sb ,
486
+ };
487
+ struct file * file ;
488
+ static bool rescan_done = true;
489
+
490
+ if (action == PM_HIBERNATION_PREPARE ) {
491
+ rescan_done = false;
492
+ return NOTIFY_OK ;
493
+ } else if (action != PM_POST_HIBERNATION ) {
494
+ return NOTIFY_DONE ;
495
+ }
496
+
497
+ if (rescan_done )
498
+ return NOTIFY_DONE ;
499
+
500
+ pr_info ("efivarfs: resyncing variable state\n" );
501
+
502
+ /* O_NOATIME is required to prevent oops on NULL mnt */
503
+ file = kernel_file_open (& path , O_RDONLY | O_DIRECTORY | O_NOATIME ,
504
+ current_cred ());
505
+ if (IS_ERR (file ))
506
+ return NOTIFY_DONE ;
507
+
508
+ rescan_done = true;
509
+
510
+ /*
511
+ * First loop over the directory and verify each entry exists,
512
+ * removing it if it doesn't
513
+ */
514
+ file -> f_pos = 2 ; /* skip . and .. */
515
+ do {
516
+ ectx .dentry = NULL ;
517
+ iterate_dir (file , & ectx .ctx );
518
+ if (ectx .dentry ) {
519
+ pr_info ("efivarfs: removing variable %pd\n" ,
520
+ ectx .dentry );
521
+ simple_recursive_removal (ectx .dentry , NULL );
522
+ dput (ectx .dentry );
523
+ }
524
+ } while (ectx .dentry );
525
+ fput (file );
526
+
527
+ /*
528
+ * then loop over variables, creating them if there's no matching
529
+ * dentry
530
+ */
531
+ efivar_init (efivarfs_check_missing , sfi -> sb , false);
532
+
533
+ return NOTIFY_OK ;
534
+ }
535
+
393
536
static int efivarfs_init_fs_context (struct fs_context * fc )
394
537
{
395
538
struct efivarfs_fs_info * sfi ;
@@ -406,6 +549,11 @@ static int efivarfs_init_fs_context(struct fs_context *fc)
406
549
407
550
fc -> s_fs_info = sfi ;
408
551
fc -> ops = & efivarfs_context_ops ;
552
+
553
+ sfi -> pm_nb .notifier_call = efivarfs_pm_notify ;
554
+ sfi -> pm_nb .priority = 0 ;
555
+ register_pm_notifier (& sfi -> pm_nb );
556
+
409
557
return 0 ;
410
558
}
411
559
@@ -415,6 +563,7 @@ static void efivarfs_kill_sb(struct super_block *sb)
415
563
416
564
blocking_notifier_chain_unregister (& efivar_ops_nh , & sfi -> nb );
417
565
kill_litter_super (sb );
566
+ unregister_pm_notifier (& sfi -> pm_nb );
418
567
419
568
kfree (sfi );
420
569
}
0 commit comments