grace.c (3431B)
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 * @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 */ 53void 54locks_end_grace(struct lock_manager *lm) 55{ 56 spin_lock(&grace_lock); 57 list_del_init(&lm->list); 58 spin_unlock(&grace_lock); 59} 60EXPORT_SYMBOL_GPL(locks_end_grace); 61 62static 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 */ 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)