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 13static unsigned int grace_net_id; 14static 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 */ 28void 29locks_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} 41EXPORT_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 */ 54void 55locks_end_grace(struct lock_manager *lm) 56{ 57 spin_lock(&grace_lock); 58 list_del_init(&lm->list); 59 spin_unlock(&grace_lock); 60} 61EXPORT_SYMBOL_GPL(locks_end_grace); 62 63static 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 * 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 */ 90bool locks_in_grace(struct net *net) 91{ 92 return __state_in_grace(net, false); 93} 94EXPORT_SYMBOL_GPL(locks_in_grace); 95 96bool opens_in_grace(struct net *net) 97{ 98 return __state_in_grace(net, true); 99} 100EXPORT_SYMBOL_GPL(opens_in_grace); 101 102static int __net_init 103grace_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 111static void __net_exit 112grace_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 121static 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 128static int __init 129init_grace(void) 130{ 131 return register_pernet_subsys(&grace_net_ops); 132} 133 134static void __exit 135exit_grace(void) 136{ 137 unregister_pernet_subsys(&grace_net_ops); 138} 139 140MODULE_AUTHOR("Jeff Layton <jlayton@primarydata.com>"); 141MODULE_LICENSE("GPL"); 142module_init(init_grace) 143module_exit(exit_grace) 144