linux/fs/nfs_common/grace.c
<<
>>
Prefs
   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 * @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 */
  91bool locks_in_grace(struct net *net)
  92{
  93        return __state_in_grace(net, false);
  94}
  95EXPORT_SYMBOL_GPL(locks_in_grace);
  96
  97bool opens_in_grace(struct net *net)
  98{
  99        return __state_in_grace(net, true);
 100}
 101EXPORT_SYMBOL_GPL(opens_in_grace);
 102
 103static int __net_init
 104grace_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
 112static void __net_exit
 113grace_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
 122static 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
 129static int __init
 130init_grace(void)
 131{
 132        return register_pernet_subsys(&grace_net_ops);
 133}
 134
 135static void __exit
 136exit_grace(void)
 137{
 138        unregister_pernet_subsys(&grace_net_ops);
 139}
 140
 141MODULE_AUTHOR("Jeff Layton <jlayton@primarydata.com>");
 142MODULE_LICENSE("GPL");
 143module_init(init_grace)
 144module_exit(exit_grace)
 145