1313#include <linux/pagemap.h>
1414#include <linux/ucs2_string.h>
1515#include <linux/slab.h>
16+ #include <linux/suspend.h>
1617#include <linux/magic.h>
1718#include <linux/statfs.h>
1819#include <linux/notifier.h>
@@ -366,7 +367,7 @@ static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc)
366367 if (err )
367368 return err ;
368369
369- return efivar_init (efivarfs_callback , sb );
370+ return efivar_init (efivarfs_callback , sb , true );
370371}
371372
372373static int efivarfs_get_tree (struct fs_context * fc )
@@ -390,6 +391,148 @@ static const struct fs_context_operations efivarfs_context_ops = {
390391 .reconfigure = efivarfs_reconfigure ,
391392};
392393
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+
393536static int efivarfs_init_fs_context (struct fs_context * fc )
394537{
395538 struct efivarfs_fs_info * sfi ;
@@ -406,6 +549,11 @@ static int efivarfs_init_fs_context(struct fs_context *fc)
406549
407550 fc -> s_fs_info = sfi ;
408551 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+
409557 return 0 ;
410558}
411559
@@ -415,6 +563,7 @@ static void efivarfs_kill_sb(struct super_block *sb)
415563
416564 blocking_notifier_chain_unregister (& efivar_ops_nh , & sfi -> nb );
417565 kill_litter_super (sb );
566+ unregister_pm_notifier (& sfi -> pm_nb );
418567
419568 kfree (sfi );
420569}
0 commit comments