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 #include <linux/filelock.h> 13 14 static unsigned int grace_net_id; 15 static DEFINE_SPINLOCK(grace_lock); 16 17 /** 18 * locks_start_grace 19 * @net: net namespace that this lock manager belongs to 20 * @lm: who this grace period is for 21 * 22 * A grace period is a period during which locks should not be given 23 * out. Currently grace periods are only enforced by the two lock 24 * managers (lockd and nfsd), using the locks_in_grace() function to 25 * check when they are in a grace period. 26 * 27 * This function is called to start a grace period. 28 */ 29 void 30 locks_start_grace(struct net *net, struct lock_manager *lm) 31 { 32 struct list_head *grace_list = net_generic(net, grace_net_id); 33 34 spin_lock(&grace_lock); 35 if (list_empty(&lm->list)) 36 list_add(&lm->list, grace_list); 37 else 38 WARN(1, "double list_add attempt detected in net %x %s\n", 39 net->ns.inum, (net == &init_net) ? "(init_net)" : ""); 40 spin_unlock(&grace_lock); 41 } 42 EXPORT_SYMBOL_GPL(locks_start_grace); 43 44 /** 45 * locks_end_grace 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 locks_end_grace(struct lock_manager *lm) 56 { 57 spin_lock(&grace_lock); 58 list_del_init(&lm->list); 59 spin_unlock(&grace_lock); 60 } 61 EXPORT_SYMBOL_GPL(locks_end_grace); 62 63 static bool 64 __state_in_grace(struct net *net, bool open) 65 { 66 struct list_head *grace_list = net_generic(net, grace_net_id); 67 struct lock_manager *lm; 68 69 if (!open) 70 return !list_empty(grace_list); 71 72 spin_lock(&grace_lock); 73 list_for_each_entry(lm, grace_list, list) { 74 if (lm->block_opens) { 75 spin_unlock(&grace_lock); 76 return true; 77 } 78 } 79 spin_unlock(&grace_lock); 80 return false; 81 } 82 83 /** 84 * locks_in_grace 85 * @net: network namespace 86 * 87 * Lock managers call this function to determine when it is OK for them 88 * to answer ordinary lock requests, and when they should accept only 89 * lock reclaims. 90 */ 91 bool locks_in_grace(struct net *net) 92 { 93 return __state_in_grace(net, false); 94 } 95 EXPORT_SYMBOL_GPL(locks_in_grace); 96 97 bool opens_in_grace(struct net *net) 98 { 99 return __state_in_grace(net, true); 100 } 101 EXPORT_SYMBOL_GPL(opens_in_grace); 102 103 static int __net_init 104 grace_init_net(struct net *net) 105 { 106 struct list_head *grace_list = net_generic(net, grace_net_id); 107 108 INIT_LIST_HEAD(grace_list); 109 return 0; 110 } 111 112 static void __net_exit 113 grace_exit_net(struct net *net) 114 { 115 struct list_head *grace_list = net_generic(net, grace_net_id); 116 117 WARN_ONCE(!list_empty(grace_list), 118 "net %x %s: grace_list is not empty\n", 119 net->ns.inum, __func__); 120 } 121 122 static struct pernet_operations grace_net_ops = { 123 .init = grace_init_net, 124 .exit = grace_exit_net, 125 .id = &grace_net_id, 126 .size = sizeof(struct list_head), 127 }; 128 129 static int __init 130 init_grace(void) 131 { 132 return register_pernet_subsys(&grace_net_ops); 133 } 134 135 static void __exit 136 exit_grace(void) 137 { 138 unregister_pernet_subsys(&grace_net_ops); 139 } 140 141 MODULE_AUTHOR("Jeff Layton <jlayton@primarydata.com>"); 142 MODULE_DESCRIPTION("NFS client and server infrastructure"); 143 MODULE_LICENSE("GPL"); 144 module_init(init_grace) 145 module_exit(exit_grace) 146
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.