1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Common code for control of lockd and nfsv4 grace periods. 4 * 5 * Transplanted from lockd code 6 */ 7 8 #include <linux/module.h> 9 #include <net/net_namespace.h> 10 #include <net/netns/generic.h> 11 #include <linux/fs.h> 12 13 static unsigned int grace_net_id; 14 static DEFINE_SPINLOCK(grace_lock); 15 16 /** 17 * locks_start_grace 18 * @net: net namespace that this lock manager belongs to 19 * @lm: who this grace period is for 20 * 21 * A grace period is a period during which locks should not be given 22 * out. Currently grace periods are only enforced by the two lock 23 * managers (lockd and nfsd), using the locks_in_grace() function to 24 * check when they are in a grace period. 25 * 26 * This function is called to start a grace period. 27 */ 28 void 29 locks_start_grace(struct net *net, struct lock_manager *lm) 30 { 31 struct list_head *grace_list = net_generic(net, grace_net_id); 32 33 spin_lock(&grace_lock); 34 if (list_empty(&lm->list)) 35 list_add(&lm->list, grace_list); 36 else 37 WARN(1, "double list_add attempt detected in net %x %s\n", 38 net->ns.inum, (net == &init_net) ? "(init_net)" : ""); 39 spin_unlock(&grace_lock); 40 } 41 EXPORT_SYMBOL_GPL(locks_start_grace); 42 43 /** 44 * locks_end_grace 45 * @lm: who this grace period is for 46 * 47 * Call this function to state that the given lock manager is ready to 48 * resume regular locking. The grace period will not end until all lock 49 * managers that called locks_start_grace() also call locks_end_grace(). 50 * Note that callers count on it being safe to call this more than once, 51 * and the second call should be a no-op. 52 */ 53 void 54 locks_end_grace(struct lock_manager *lm) 55 { 56 spin_lock(&grace_lock); 57 list_del_init(&lm->list); 58 spin_unlock(&grace_lock); 59 } 60 EXPORT_SYMBOL_GPL(locks_end_grace); 61 62 static bool 63 __state_in_grace(struct net *net, bool open) 64 { 65 struct list_head *grace_list = net_generic(net, grace_net_id); 66 struct lock_manager *lm; 67 68 if (!open) 69 return !list_empty(grace_list); 70 71 spin_lock(&grace_lock); 72 list_for_each_entry(lm, grace_list, list) { 73 if (lm->block_opens) { 74 spin_unlock(&grace_lock); 75 return true; 76 } 77 } 78 spin_unlock(&grace_lock); 79 return false; 80 } 81 82 /** 83 * locks_in_grace 84 * @net: network namespace 85 * 86 * Lock managers call this function to determine when it is OK for them 87 * to answer ordinary lock requests, and when they should accept only 88 * lock reclaims. 89 */ 90 bool locks_in_grace(struct net *net) 91 { 92 return __state_in_grace(net, false); 93 } 94 EXPORT_SYMBOL_GPL(locks_in_grace); 95 96 bool opens_in_grace(struct net *net) 97 { 98 return __state_in_grace(net, true); 99 } 100 EXPORT_SYMBOL_GPL(opens_in_grace); 101 102 static int __net_init 103 grace_init_net(struct net *net) 104 { 105 struct list_head *grace_list = net_generic(net, grace_net_id); 106 107 INIT_LIST_HEAD(grace_list); 108 return 0; 109 } 110 111 static void __net_exit 112 grace_exit_net(struct net *net) 113 { 114 struct list_head *grace_list = net_generic(net, grace_net_id); 115 116 WARN_ONCE(!list_empty(grace_list), 117 "net %x %s: grace_list is not empty\n", 118 net->ns.inum, __func__); 119 } 120 121 static struct pernet_operations grace_net_ops = { 122 .init = grace_init_net, 123 .exit = grace_exit_net, 124 .id = &grace_net_id, 125 .size = sizeof(struct list_head), 126 }; 127 128 static int __init 129 init_grace(void) 130 { 131 return register_pernet_subsys(&grace_net_ops); 132 } 133 134 static void __exit 135 exit_grace(void) 136 { 137 unregister_pernet_subsys(&grace_net_ops); 138 } 139 140 MODULE_AUTHOR("Jeff Layton <jlayton@primarydata.com>"); 141 MODULE_LICENSE("GPL"); 142 module_init(init_grace) 143 module_exit(exit_grace) 144