diff options
Diffstat (limited to 'fs/quota/quota.c')
-rw-r--r-- | fs/quota/quota.c | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 95c5b42384b2..ee91e2756950 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/capability.h> | 18 | #include <linux/capability.h> |
19 | #include <linux/quotaops.h> | 19 | #include <linux/quotaops.h> |
20 | #include <linux/types.h> | 20 | #include <linux/types.h> |
21 | #include <net/netlink.h> | ||
22 | #include <net/genetlink.h> | ||
21 | 23 | ||
22 | /* Check validity of generic quotactl commands */ | 24 | /* Check validity of generic quotactl commands */ |
23 | static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, | 25 | static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, |
@@ -525,3 +527,94 @@ asmlinkage long sys32_quotactl(unsigned int cmd, const char __user *special, | |||
525 | return ret; | 527 | return ret; |
526 | } | 528 | } |
527 | #endif | 529 | #endif |
530 | |||
531 | |||
532 | #ifdef CONFIG_QUOTA_NETLINK_INTERFACE | ||
533 | |||
534 | /* Netlink family structure for quota */ | ||
535 | static struct genl_family quota_genl_family = { | ||
536 | .id = GENL_ID_GENERATE, | ||
537 | .hdrsize = 0, | ||
538 | .name = "VFS_DQUOT", | ||
539 | .version = 1, | ||
540 | .maxattr = QUOTA_NL_A_MAX, | ||
541 | }; | ||
542 | |||
543 | /** | ||
544 | * quota_send_warning - Send warning to userspace about exceeded quota | ||
545 | * @type: The quota type: USRQQUOTA, GRPQUOTA,... | ||
546 | * @id: The user or group id of the quota that was exceeded | ||
547 | * @dev: The device on which the fs is mounted (sb->s_dev) | ||
548 | * @warntype: The type of the warning: QUOTA_NL_... | ||
549 | * | ||
550 | * This can be used by filesystems (including those which don't use | ||
551 | * dquot) to send a message to userspace relating to quota limits. | ||
552 | * | ||
553 | */ | ||
554 | |||
555 | void quota_send_warning(short type, unsigned int id, dev_t dev, | ||
556 | const char warntype) | ||
557 | { | ||
558 | static atomic_t seq; | ||
559 | struct sk_buff *skb; | ||
560 | void *msg_head; | ||
561 | int ret; | ||
562 | int msg_size = 4 * nla_total_size(sizeof(u32)) + | ||
563 | 2 * nla_total_size(sizeof(u64)); | ||
564 | |||
565 | /* We have to allocate using GFP_NOFS as we are called from a | ||
566 | * filesystem performing write and thus further recursion into | ||
567 | * the fs to free some data could cause deadlocks. */ | ||
568 | skb = genlmsg_new(msg_size, GFP_NOFS); | ||
569 | if (!skb) { | ||
570 | printk(KERN_ERR | ||
571 | "VFS: Not enough memory to send quota warning.\n"); | ||
572 | return; | ||
573 | } | ||
574 | msg_head = genlmsg_put(skb, 0, atomic_add_return(1, &seq), | ||
575 | "a_genl_family, 0, QUOTA_NL_C_WARNING); | ||
576 | if (!msg_head) { | ||
577 | printk(KERN_ERR | ||
578 | "VFS: Cannot store netlink header in quota warning.\n"); | ||
579 | goto err_out; | ||
580 | } | ||
581 | ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, type); | ||
582 | if (ret) | ||
583 | goto attr_err_out; | ||
584 | ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, id); | ||
585 | if (ret) | ||
586 | goto attr_err_out; | ||
587 | ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype); | ||
588 | if (ret) | ||
589 | goto attr_err_out; | ||
590 | ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MAJOR, MAJOR(dev)); | ||
591 | if (ret) | ||
592 | goto attr_err_out; | ||
593 | ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, MINOR(dev)); | ||
594 | if (ret) | ||
595 | goto attr_err_out; | ||
596 | ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid()); | ||
597 | if (ret) | ||
598 | goto attr_err_out; | ||
599 | genlmsg_end(skb, msg_head); | ||
600 | |||
601 | genlmsg_multicast(skb, 0, quota_genl_family.id, GFP_NOFS); | ||
602 | return; | ||
603 | attr_err_out: | ||
604 | printk(KERN_ERR "VFS: Not enough space to compose quota message!\n"); | ||
605 | err_out: | ||
606 | kfree_skb(skb); | ||
607 | } | ||
608 | EXPORT_SYMBOL(quota_send_warning); | ||
609 | |||
610 | static int __init quota_init(void) | ||
611 | { | ||
612 | if (genl_register_family("a_genl_family) != 0) | ||
613 | printk(KERN_ERR | ||
614 | "VFS: Failed to create quota netlink interface.\n"); | ||
615 | return 0; | ||
616 | }; | ||
617 | |||
618 | module_init(quota_init); | ||
619 | #endif | ||
620 | |||