1799a9d44SChristoph Hellwig 2799a9d44SChristoph Hellwig #include <linux/cred.h> 3799a9d44SChristoph Hellwig #include <linux/init.h> 4799a9d44SChristoph Hellwig #include <linux/module.h> 5799a9d44SChristoph Hellwig #include <linux/kernel.h> 6799a9d44SChristoph Hellwig #include <linux/quotaops.h> 7799a9d44SChristoph Hellwig #include <linux/sched.h> 85a0e3ad6STejun Heo #include <linux/slab.h> 9799a9d44SChristoph Hellwig #include <net/netlink.h> 10799a9d44SChristoph Hellwig #include <net/genetlink.h> 11799a9d44SChristoph Hellwig 12*2a94fe48SJohannes Berg static const struct genl_multicast_group quota_mcgrps[] = { 13*2a94fe48SJohannes Berg { .name = "events", }, 14*2a94fe48SJohannes Berg }; 15*2a94fe48SJohannes Berg 16799a9d44SChristoph Hellwig /* Netlink family structure for quota */ 17799a9d44SChristoph Hellwig static struct genl_family quota_genl_family = { 182ecf7536SJohannes Berg /* 192ecf7536SJohannes Berg * Needed due to multicast group ID abuse - old code assumed 202ecf7536SJohannes Berg * the family ID was also a valid multicast group ID (which 212ecf7536SJohannes Berg * isn't true) and userspace might thus rely on it. Assign a 222ecf7536SJohannes Berg * static ID for this group to make dealing with that easier. 232ecf7536SJohannes Berg */ 242ecf7536SJohannes Berg .id = GENL_ID_VFS_DQUOT, 25799a9d44SChristoph Hellwig .hdrsize = 0, 26799a9d44SChristoph Hellwig .name = "VFS_DQUOT", 27799a9d44SChristoph Hellwig .version = 1, 28799a9d44SChristoph Hellwig .maxattr = QUOTA_NL_A_MAX, 29*2a94fe48SJohannes Berg .mcgrps = quota_mcgrps, 30*2a94fe48SJohannes Berg .n_mcgrps = ARRAY_SIZE(quota_mcgrps), 312ecf7536SJohannes Berg }; 322ecf7536SJohannes Berg 33799a9d44SChristoph Hellwig /** 34799a9d44SChristoph Hellwig * quota_send_warning - Send warning to userspace about exceeded quota 35799a9d44SChristoph Hellwig * @type: The quota type: USRQQUOTA, GRPQUOTA,... 36799a9d44SChristoph Hellwig * @id: The user or group id of the quota that was exceeded 37799a9d44SChristoph Hellwig * @dev: The device on which the fs is mounted (sb->s_dev) 38799a9d44SChristoph Hellwig * @warntype: The type of the warning: QUOTA_NL_... 39799a9d44SChristoph Hellwig * 40799a9d44SChristoph Hellwig * This can be used by filesystems (including those which don't use 41799a9d44SChristoph Hellwig * dquot) to send a message to userspace relating to quota limits. 42799a9d44SChristoph Hellwig * 43799a9d44SChristoph Hellwig */ 44799a9d44SChristoph Hellwig 45431f1974SEric W. Biederman void quota_send_warning(struct kqid qid, dev_t dev, 46799a9d44SChristoph Hellwig const char warntype) 47799a9d44SChristoph Hellwig { 48799a9d44SChristoph Hellwig static atomic_t seq; 49799a9d44SChristoph Hellwig struct sk_buff *skb; 50799a9d44SChristoph Hellwig void *msg_head; 51799a9d44SChristoph Hellwig int ret; 52799a9d44SChristoph Hellwig int msg_size = 4 * nla_total_size(sizeof(u32)) + 53799a9d44SChristoph Hellwig 2 * nla_total_size(sizeof(u64)); 54799a9d44SChristoph Hellwig 55799a9d44SChristoph Hellwig /* We have to allocate using GFP_NOFS as we are called from a 56799a9d44SChristoph Hellwig * filesystem performing write and thus further recursion into 57799a9d44SChristoph Hellwig * the fs to free some data could cause deadlocks. */ 58799a9d44SChristoph Hellwig skb = genlmsg_new(msg_size, GFP_NOFS); 59799a9d44SChristoph Hellwig if (!skb) { 60799a9d44SChristoph Hellwig printk(KERN_ERR 61799a9d44SChristoph Hellwig "VFS: Not enough memory to send quota warning.\n"); 62799a9d44SChristoph Hellwig return; 63799a9d44SChristoph Hellwig } 64799a9d44SChristoph Hellwig msg_head = genlmsg_put(skb, 0, atomic_add_return(1, &seq), 65799a9d44SChristoph Hellwig "a_genl_family, 0, QUOTA_NL_C_WARNING); 66799a9d44SChristoph Hellwig if (!msg_head) { 67799a9d44SChristoph Hellwig printk(KERN_ERR 68799a9d44SChristoph Hellwig "VFS: Cannot store netlink header in quota warning.\n"); 69799a9d44SChristoph Hellwig goto err_out; 70799a9d44SChristoph Hellwig } 71431f1974SEric W. Biederman ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, qid.type); 72799a9d44SChristoph Hellwig if (ret) 73799a9d44SChristoph Hellwig goto attr_err_out; 74431f1974SEric W. Biederman ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, 75431f1974SEric W. Biederman from_kqid_munged(&init_user_ns, qid)); 76799a9d44SChristoph Hellwig if (ret) 77799a9d44SChristoph Hellwig goto attr_err_out; 78799a9d44SChristoph Hellwig ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype); 79799a9d44SChristoph Hellwig if (ret) 80799a9d44SChristoph Hellwig goto attr_err_out; 81799a9d44SChristoph Hellwig ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MAJOR, MAJOR(dev)); 82799a9d44SChristoph Hellwig if (ret) 83799a9d44SChristoph Hellwig goto attr_err_out; 84799a9d44SChristoph Hellwig ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, MINOR(dev)); 85799a9d44SChristoph Hellwig if (ret) 86799a9d44SChristoph Hellwig goto attr_err_out; 87431f1974SEric W. Biederman ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, 88431f1974SEric W. Biederman from_kuid_munged(&init_user_ns, current_uid())); 89799a9d44SChristoph Hellwig if (ret) 90799a9d44SChristoph Hellwig goto attr_err_out; 91799a9d44SChristoph Hellwig genlmsg_end(skb, msg_head); 92799a9d44SChristoph Hellwig 93*2a94fe48SJohannes Berg genlmsg_multicast("a_genl_family, skb, 0, 0, GFP_NOFS); 94799a9d44SChristoph Hellwig return; 95799a9d44SChristoph Hellwig attr_err_out: 96799a9d44SChristoph Hellwig printk(KERN_ERR "VFS: Not enough space to compose quota message!\n"); 97799a9d44SChristoph Hellwig err_out: 98799a9d44SChristoph Hellwig kfree_skb(skb); 99799a9d44SChristoph Hellwig } 100799a9d44SChristoph Hellwig EXPORT_SYMBOL(quota_send_warning); 101799a9d44SChristoph Hellwig 102799a9d44SChristoph Hellwig static int __init quota_init(void) 103799a9d44SChristoph Hellwig { 104799a9d44SChristoph Hellwig if (genl_register_family("a_genl_family) != 0) 105799a9d44SChristoph Hellwig printk(KERN_ERR 106799a9d44SChristoph Hellwig "VFS: Failed to create quota netlink interface.\n"); 107799a9d44SChristoph Hellwig return 0; 108799a9d44SChristoph Hellwig }; 109799a9d44SChristoph Hellwig 110799a9d44SChristoph Hellwig module_init(quota_init); 111