20
20
#include <linux/printk.h>
21
21
22
22
#include "internal.h"
23
+ #include "../internal.h"
23
24
24
25
static int efivarfs_ops_notifier (struct notifier_block * nb , unsigned long event ,
25
26
void * data )
@@ -119,12 +120,18 @@ static int efivarfs_statfs(struct dentry *dentry, struct kstatfs *buf)
119
120
120
121
return 0 ;
121
122
}
123
+
124
+ static int efivarfs_freeze_fs (struct super_block * sb );
125
+ static int efivarfs_unfreeze_fs (struct super_block * sb );
126
+
122
127
static const struct super_operations efivarfs_ops = {
123
128
.statfs = efivarfs_statfs ,
124
129
.drop_inode = generic_delete_inode ,
125
130
.alloc_inode = efivarfs_alloc_inode ,
126
131
.free_inode = efivarfs_free_inode ,
127
132
.show_options = efivarfs_show_options ,
133
+ .freeze_fs = efivarfs_freeze_fs ,
134
+ .unfreeze_fs = efivarfs_unfreeze_fs ,
128
135
};
129
136
130
137
/*
@@ -367,8 +374,6 @@ static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc)
367
374
if (err )
368
375
return err ;
369
376
370
- register_pm_notifier (& sfi -> pm_nb );
371
-
372
377
return efivar_init (efivarfs_callback , sb , true);
373
378
}
374
379
@@ -393,48 +398,6 @@ static const struct fs_context_operations efivarfs_context_ops = {
393
398
.reconfigure = efivarfs_reconfigure ,
394
399
};
395
400
396
- struct efivarfs_ctx {
397
- struct dir_context ctx ;
398
- struct super_block * sb ;
399
- struct dentry * dentry ;
400
- };
401
-
402
- static bool efivarfs_actor (struct dir_context * ctx , const char * name , int len ,
403
- loff_t offset , u64 ino , unsigned mode )
404
- {
405
- unsigned long size ;
406
- struct efivarfs_ctx * ectx = container_of (ctx , struct efivarfs_ctx , ctx );
407
- struct qstr qstr = { .name = name , .len = len };
408
- struct dentry * dentry = d_hash_and_lookup (ectx -> sb -> s_root , & qstr );
409
- struct inode * inode ;
410
- struct efivar_entry * entry ;
411
- int err ;
412
-
413
- if (IS_ERR_OR_NULL (dentry ))
414
- return true;
415
-
416
- inode = d_inode (dentry );
417
- entry = efivar_entry (inode );
418
-
419
- err = efivar_entry_size (entry , & size );
420
- size += sizeof (__u32 ); /* attributes */
421
- if (err )
422
- size = 0 ;
423
-
424
- inode_lock_nested (inode , I_MUTEX_CHILD );
425
- i_size_write (inode , size );
426
- inode_unlock (inode );
427
-
428
- if (!size ) {
429
- ectx -> dentry = dentry ;
430
- return false;
431
- }
432
-
433
- dput (dentry );
434
-
435
- return true;
436
- }
437
-
438
401
static int efivarfs_check_missing (efi_char16_t * name16 , efi_guid_t vendor ,
439
402
unsigned long name_size , void * data )
440
403
{
@@ -474,111 +437,59 @@ static int efivarfs_check_missing(efi_char16_t *name16, efi_guid_t vendor,
474
437
return err ;
475
438
}
476
439
477
- static void efivarfs_deactivate_super_work (struct work_struct * work )
478
- {
479
- struct super_block * s = container_of (work , struct super_block ,
480
- destroy_work );
481
- /*
482
- * note: here s->destroy_work is free for reuse (which
483
- * will happen in deactivate_super)
484
- */
485
- deactivate_super (s );
486
- }
487
-
488
440
static struct file_system_type efivarfs_type ;
489
441
490
- static int efivarfs_pm_notify (struct notifier_block * nb , unsigned long action ,
491
- void * ptr )
442
+ static int efivarfs_freeze_fs (struct super_block * sb )
492
443
{
493
- struct efivarfs_fs_info * sfi = container_of (nb , struct efivarfs_fs_info ,
494
- pm_nb );
495
- struct path path ;
496
- struct efivarfs_ctx ectx = {
497
- .ctx = {
498
- .actor = efivarfs_actor ,
499
- },
500
- .sb = sfi -> sb ,
501
- };
502
- struct file * file ;
503
- struct super_block * s = sfi -> sb ;
504
- static bool rescan_done = true;
505
-
506
- if (action == PM_HIBERNATION_PREPARE ) {
507
- rescan_done = false;
508
- return NOTIFY_OK ;
509
- } else if (action != PM_POST_HIBERNATION ) {
510
- return NOTIFY_DONE ;
511
- }
512
-
513
- if (rescan_done )
514
- return NOTIFY_DONE ;
515
-
516
- /* ensure single superblock is alive and pin it */
517
- if (!atomic_inc_not_zero (& s -> s_active ))
518
- return NOTIFY_DONE ;
519
-
520
- pr_info ("efivarfs: resyncing variable state\n" );
521
-
522
- path .dentry = sfi -> sb -> s_root ;
523
-
524
- /*
525
- * do not add SB_KERNMOUNT which a single superblock could
526
- * expose to userspace and which also causes MNT_INTERNAL, see
527
- * below
528
- */
529
- path .mnt = vfs_kern_mount (& efivarfs_type , 0 ,
530
- efivarfs_type .name , NULL );
531
- if (IS_ERR (path .mnt )) {
532
- pr_err ("efivarfs: internal mount failed\n" );
533
- /*
534
- * We may be the last pinner of the superblock but
535
- * calling efivarfs_kill_sb from within the notifier
536
- * here would deadlock trying to unregister it
537
- */
538
- INIT_WORK (& s -> destroy_work , efivarfs_deactivate_super_work );
539
- schedule_work (& s -> destroy_work );
540
- return PTR_ERR (path .mnt );
541
- }
542
-
543
- /* path.mnt now has pin on superblock, so this must be above one */
544
- atomic_dec (& s -> s_active );
545
-
546
- file = kernel_file_open (& path , O_RDONLY | O_DIRECTORY | O_NOATIME ,
547
- current_cred ());
548
- /*
549
- * safe even if last put because no MNT_INTERNAL means this
550
- * will do delayed deactivate_super and not deadlock
551
- */
552
- mntput (path .mnt );
553
- if (IS_ERR (file ))
554
- return NOTIFY_DONE ;
444
+ /* Nothing for us to do. */
445
+ return 0 ;
446
+ }
555
447
556
- rescan_done = true;
448
+ static int efivarfs_unfreeze_fs (struct super_block * sb )
449
+ {
450
+ struct dentry * child = NULL ;
557
451
558
452
/*
559
- * First loop over the directory and verify each entry exists,
560
- * removing it if it doesn't
453
+ * Unconditionally resync the variable state on a thaw request.
454
+ * Given the size of efivarfs it really doesn't matter to simply
455
+ * iterate through all of the entries and resync. Freeze/thaw
456
+ * requests are rare enough for that to not matter and the
457
+ * number of entries is pretty low too. So we really don't care.
561
458
*/
562
- file -> f_pos = 2 ; /* skip . and .. */
563
- do {
564
- ectx .dentry = NULL ;
565
- iterate_dir (file , & ectx .ctx );
566
- if (ectx .dentry ) {
567
- pr_info ("efivarfs: removing variable %pd\n" ,
568
- ectx .dentry );
569
- simple_recursive_removal (ectx .dentry , NULL );
570
- dput (ectx .dentry );
459
+ pr_info ("efivarfs: resyncing variable state\n" );
460
+ for (;;) {
461
+ int err ;
462
+ unsigned long size = 0 ;
463
+ struct inode * inode ;
464
+ struct efivar_entry * entry ;
465
+
466
+ child = find_next_child (sb -> s_root , child );
467
+ if (!child )
468
+ break ;
469
+
470
+ inode = d_inode (child );
471
+ entry = efivar_entry (inode );
472
+
473
+ err = efivar_entry_size (entry , & size );
474
+ if (err )
475
+ size = 0 ;
476
+ else
477
+ size += sizeof (__u32 );
478
+
479
+ inode_lock (inode );
480
+ i_size_write (inode , size );
481
+ inode_unlock (inode );
482
+
483
+ /* The variable doesn't exist anymore, delete it. */
484
+ if (!size ) {
485
+ pr_info ("efivarfs: removing variable %pd\n" , child );
486
+ simple_recursive_removal (child , NULL );
571
487
}
572
- } while (ectx .dentry );
573
- fput (file );
574
-
575
- /*
576
- * then loop over variables, creating them if there's no matching
577
- * dentry
578
- */
579
- efivar_init (efivarfs_check_missing , sfi -> sb , false);
488
+ }
580
489
581
- return NOTIFY_OK ;
490
+ efivar_init (efivarfs_check_missing , sb , false);
491
+ pr_info ("efivarfs: finished resyncing variable state\n" );
492
+ return 0 ;
582
493
}
583
494
584
495
static int efivarfs_init_fs_context (struct fs_context * fc )
@@ -598,9 +509,6 @@ static int efivarfs_init_fs_context(struct fs_context *fc)
598
509
fc -> s_fs_info = sfi ;
599
510
fc -> ops = & efivarfs_context_ops ;
600
511
601
- sfi -> pm_nb .notifier_call = efivarfs_pm_notify ;
602
- sfi -> pm_nb .priority = 0 ;
603
-
604
512
return 0 ;
605
513
}
606
514
@@ -610,7 +518,6 @@ static void efivarfs_kill_sb(struct super_block *sb)
610
518
611
519
blocking_notifier_chain_unregister (& efivar_ops_nh , & sfi -> nb );
612
520
kill_litter_super (sb );
613
- unregister_pm_notifier (& sfi -> pm_nb );
614
521
615
522
kfree (sfi );
616
523
}
0 commit comments