Branch data Line data Source code
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 : 0 : locks_start_grace(struct net *net, struct lock_manager *lm) 30 : : { 31 : 0 : struct list_head *grace_list = net_generic(net, grace_net_id); 32 : : 33 : : spin_lock(&grace_lock); 34 [ # # ]: 0 : if (list_empty(&lm->list)) 35 : : list_add(&lm->list, grace_list); 36 : : else 37 [ # # ]: 0 : 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 : 0 : } 41 : : EXPORT_SYMBOL_GPL(locks_start_grace); 42 : : 43 : : /** 44 : : * locks_end_grace 45 : : * @net: net namespace that this lock manager belongs to 46 : : * @lm: who this grace period is for 47 : : * 48 : : * Call this function to state that the given lock manager is ready to 49 : : * resume regular locking. The grace period will not end until all lock 50 : : * managers that called locks_start_grace() also call locks_end_grace(). 51 : : * Note that callers count on it being safe to call this more than once, 52 : : * and the second call should be a no-op. 53 : : */ 54 : : void 55 : 0 : locks_end_grace(struct lock_manager *lm) 56 : : { 57 : : spin_lock(&grace_lock); 58 : 0 : list_del_init(&lm->list); 59 : : spin_unlock(&grace_lock); 60 : 0 : } 61 : : EXPORT_SYMBOL_GPL(locks_end_grace); 62 : : 63 : : static bool 64 : 0 : __state_in_grace(struct net *net, bool open) 65 : : { 66 : 0 : struct list_head *grace_list = net_generic(net, grace_net_id); 67 : : struct lock_manager *lm; 68 : : 69 [ # # ]: 0 : if (!open) 70 : 0 : return !list_empty(grace_list); 71 : : 72 [ # # ]: 0 : list_for_each_entry(lm, grace_list, list) { 73 [ # # ]: 0 : if (lm->block_opens) 74 : : return true; 75 : : } 76 : : return false; 77 : : } 78 : : 79 : : /** 80 : : * locks_in_grace 81 : : * 82 : : * Lock managers call this function to determine when it is OK for them 83 : : * to answer ordinary lock requests, and when they should accept only 84 : : * lock reclaims. 85 : : */ 86 : 0 : bool locks_in_grace(struct net *net) 87 : : { 88 : 0 : return __state_in_grace(net, false); 89 : : } 90 : : EXPORT_SYMBOL_GPL(locks_in_grace); 91 : : 92 : 0 : bool opens_in_grace(struct net *net) 93 : : { 94 : 0 : return __state_in_grace(net, true); 95 : : } 96 : : EXPORT_SYMBOL_GPL(opens_in_grace); 97 : : 98 : : static int __net_init 99 : 207 : grace_init_net(struct net *net) 100 : : { 101 : 207 : struct list_head *grace_list = net_generic(net, grace_net_id); 102 : : 103 : : INIT_LIST_HEAD(grace_list); 104 : 207 : return 0; 105 : : } 106 : : 107 : : static void __net_exit 108 : 0 : grace_exit_net(struct net *net) 109 : : { 110 : 0 : struct list_head *grace_list = net_generic(net, grace_net_id); 111 : : 112 [ # # # # ]: 0 : WARN_ONCE(!list_empty(grace_list), 113 : : "net %x %s: grace_list is not empty\n", 114 : : net->ns.inum, __func__); 115 : 0 : } 116 : : 117 : : static struct pernet_operations grace_net_ops = { 118 : : .init = grace_init_net, 119 : : .exit = grace_exit_net, 120 : : .id = &grace_net_id, 121 : : .size = sizeof(struct list_head), 122 : : }; 123 : : 124 : : static int __init 125 : 207 : init_grace(void) 126 : : { 127 : 207 : return register_pernet_subsys(&grace_net_ops); 128 : : } 129 : : 130 : : static void __exit 131 : 0 : exit_grace(void) 132 : : { 133 : 0 : unregister_pernet_subsys(&grace_net_ops); 134 : 0 : } 135 : : 136 : : MODULE_AUTHOR("Jeff Layton <jlayton@primarydata.com>"); 137 : : MODULE_LICENSE("GPL"); 138 : : module_init(init_grace) 139 : : module_exit(exit_grace)