hc
2024-08-16 a24a44ff9ca902811b99aa9663d697cf452e08ef
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// SPDX-License-Identifier: GPL-2.0
#include <linux/cred.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/quotaops.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <net/netlink.h>
#include <net/genetlink.h>
 
static const struct genl_multicast_group quota_mcgrps[] = {
   { .name = "events", },
};
 
/* Netlink family structure for quota */
static struct genl_family quota_genl_family __ro_after_init = {
   .module = THIS_MODULE,
   .hdrsize = 0,
   .name = "VFS_DQUOT",
   .version = 1,
   .maxattr = QUOTA_NL_A_MAX,
   .mcgrps = quota_mcgrps,
   .n_mcgrps = ARRAY_SIZE(quota_mcgrps),
};
 
/**
 * quota_send_warning - Send warning to userspace about exceeded quota
 * @qid: The kernel internal quota identifier.
 * @dev: The device on which the fs is mounted (sb->s_dev)
 * @warntype: The type of the warning: QUOTA_NL_...
 *
 * This can be used by filesystems (including those which don't use
 * dquot) to send a message to userspace relating to quota limits.
 *
 */
 
void quota_send_warning(struct kqid qid, dev_t dev,
           const char warntype)
{
   static atomic_t seq;
   struct sk_buff *skb;
   void *msg_head;
   int ret;
   int msg_size = 4 * nla_total_size(sizeof(u32)) +
              2 * nla_total_size_64bit(sizeof(u64));
 
   /* We have to allocate using GFP_NOFS as we are called from a
    * filesystem performing write and thus further recursion into
    * the fs to free some data could cause deadlocks. */
   skb = genlmsg_new(msg_size, GFP_NOFS);
   if (!skb) {
       printk(KERN_ERR
         "VFS: Not enough memory to send quota warning.\n");
       return;
   }
   msg_head = genlmsg_put(skb, 0, atomic_add_return(1, &seq),
           &quota_genl_family, 0, QUOTA_NL_C_WARNING);
   if (!msg_head) {
       printk(KERN_ERR
         "VFS: Cannot store netlink header in quota warning.\n");
       goto err_out;
   }
   ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, qid.type);
   if (ret)
       goto attr_err_out;
   ret = nla_put_u64_64bit(skb, QUOTA_NL_A_EXCESS_ID,
               from_kqid_munged(&init_user_ns, qid),
               QUOTA_NL_A_PAD);
   if (ret)
       goto attr_err_out;
   ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype);
   if (ret)
       goto attr_err_out;
   ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MAJOR, MAJOR(dev));
   if (ret)
       goto attr_err_out;
   ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, MINOR(dev));
   if (ret)
       goto attr_err_out;
   ret = nla_put_u64_64bit(skb, QUOTA_NL_A_CAUSED_ID,
               from_kuid_munged(&init_user_ns, current_uid()),
               QUOTA_NL_A_PAD);
   if (ret)
       goto attr_err_out;
   genlmsg_end(skb, msg_head);
 
   genlmsg_multicast(&quota_genl_family, skb, 0, 0, GFP_NOFS);
   return;
attr_err_out:
   printk(KERN_ERR "VFS: Not enough space to compose quota message!\n");
err_out:
   kfree_skb(skb);
}
EXPORT_SYMBOL(quota_send_warning);
 
static int __init quota_init(void)
{
   if (genl_register_family(&quota_genl_family) != 0)
       printk(KERN_ERR
              "VFS: Failed to create quota netlink interface.\n");
   return 0;
};
fs_initcall(quota_init);