diff options
| -rw-r--r-- | fs/quota/Kconfig | 2 | ||||
| -rw-r--r-- | fs/quota/dquot.c | 93 | ||||
| -rw-r--r-- | fs/quota/quota.c | 93 | ||||
| -rw-r--r-- | include/linux/quota.h | 11 |
4 files changed, 114 insertions, 85 deletions
diff --git a/fs/quota/Kconfig b/fs/quota/Kconfig index 8047e01ef46b..353e78a9ebee 100644 --- a/fs/quota/Kconfig +++ b/fs/quota/Kconfig | |||
| @@ -17,7 +17,7 @@ config QUOTA | |||
| 17 | 17 | ||
| 18 | config QUOTA_NETLINK_INTERFACE | 18 | config QUOTA_NETLINK_INTERFACE |
| 19 | bool "Report quota messages through netlink interface" | 19 | bool "Report quota messages through netlink interface" |
| 20 | depends on QUOTA && NET | 20 | depends on QUOTACTL && NET |
| 21 | help | 21 | help |
| 22 | If you say Y here, quota warnings (about exceeding softlimit, reaching | 22 | If you say Y here, quota warnings (about exceeding softlimit, reaching |
| 23 | hardlimit, etc.) will be reported through netlink interface. If unsure, | 23 | hardlimit, etc.) will be reported through netlink interface. If unsure, |
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 39b49c42a7ed..9b6ad908dcb2 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c | |||
| @@ -77,10 +77,6 @@ | |||
| 77 | #include <linux/capability.h> | 77 | #include <linux/capability.h> |
| 78 | #include <linux/quotaops.h> | 78 | #include <linux/quotaops.h> |
| 79 | #include <linux/writeback.h> /* for inode_lock, oddly enough.. */ | 79 | #include <linux/writeback.h> /* for inode_lock, oddly enough.. */ |
| 80 | #ifdef CONFIG_QUOTA_NETLINK_INTERFACE | ||
| 81 | #include <net/netlink.h> | ||
| 82 | #include <net/genetlink.h> | ||
| 83 | #endif | ||
| 84 | 80 | ||
| 85 | #include <asm/uaccess.h> | 81 | #include <asm/uaccess.h> |
| 86 | 82 | ||
| @@ -1071,73 +1067,6 @@ static void print_warning(struct dquot *dquot, const int warntype) | |||
| 1071 | } | 1067 | } |
| 1072 | #endif | 1068 | #endif |
| 1073 | 1069 | ||
| 1074 | #ifdef CONFIG_QUOTA_NETLINK_INTERFACE | ||
| 1075 | |||
| 1076 | /* Netlink family structure for quota */ | ||
| 1077 | static struct genl_family quota_genl_family = { | ||
| 1078 | .id = GENL_ID_GENERATE, | ||
| 1079 | .hdrsize = 0, | ||
| 1080 | .name = "VFS_DQUOT", | ||
| 1081 | .version = 1, | ||
| 1082 | .maxattr = QUOTA_NL_A_MAX, | ||
| 1083 | }; | ||
| 1084 | |||
| 1085 | /* Send warning to userspace about user which exceeded quota */ | ||
| 1086 | static void send_warning(const struct dquot *dquot, const char warntype) | ||
| 1087 | { | ||
| 1088 | static atomic_t seq; | ||
| 1089 | struct sk_buff *skb; | ||
| 1090 | void *msg_head; | ||
| 1091 | int ret; | ||
| 1092 | int msg_size = 4 * nla_total_size(sizeof(u32)) + | ||
| 1093 | 2 * nla_total_size(sizeof(u64)); | ||
| 1094 | |||
| 1095 | /* We have to allocate using GFP_NOFS as we are called from a | ||
| 1096 | * filesystem performing write and thus further recursion into | ||
| 1097 | * the fs to free some data could cause deadlocks. */ | ||
| 1098 | skb = genlmsg_new(msg_size, GFP_NOFS); | ||
| 1099 | if (!skb) { | ||
| 1100 | printk(KERN_ERR | ||
| 1101 | "VFS: Not enough memory to send quota warning.\n"); | ||
| 1102 | return; | ||
| 1103 | } | ||
| 1104 | msg_head = genlmsg_put(skb, 0, atomic_add_return(1, &seq), | ||
| 1105 | "a_genl_family, 0, QUOTA_NL_C_WARNING); | ||
| 1106 | if (!msg_head) { | ||
| 1107 | printk(KERN_ERR | ||
| 1108 | "VFS: Cannot store netlink header in quota warning.\n"); | ||
| 1109 | goto err_out; | ||
| 1110 | } | ||
| 1111 | ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, dquot->dq_type); | ||
| 1112 | if (ret) | ||
| 1113 | goto attr_err_out; | ||
| 1114 | ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, dquot->dq_id); | ||
| 1115 | if (ret) | ||
| 1116 | goto attr_err_out; | ||
| 1117 | ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype); | ||
| 1118 | if (ret) | ||
| 1119 | goto attr_err_out; | ||
| 1120 | ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MAJOR, | ||
| 1121 | MAJOR(dquot->dq_sb->s_dev)); | ||
| 1122 | if (ret) | ||
| 1123 | goto attr_err_out; | ||
| 1124 | ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, | ||
| 1125 | MINOR(dquot->dq_sb->s_dev)); | ||
| 1126 | if (ret) | ||
| 1127 | goto attr_err_out; | ||
| 1128 | ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid()); | ||
| 1129 | if (ret) | ||
| 1130 | goto attr_err_out; | ||
| 1131 | genlmsg_end(skb, msg_head); | ||
| 1132 | |||
| 1133 | genlmsg_multicast(skb, 0, quota_genl_family.id, GFP_NOFS); | ||
| 1134 | return; | ||
| 1135 | attr_err_out: | ||
| 1136 | printk(KERN_ERR "VFS: Not enough space to compose quota message!\n"); | ||
| 1137 | err_out: | ||
| 1138 | kfree_skb(skb); | ||
| 1139 | } | ||
| 1140 | #endif | ||
| 1141 | /* | 1070 | /* |
| 1142 | * Write warnings to the console and send warning messages over netlink. | 1071 | * Write warnings to the console and send warning messages over netlink. |
| 1143 | * | 1072 | * |
| @@ -1145,18 +1074,20 @@ err_out: | |||
| 1145 | */ | 1074 | */ |
| 1146 | static void flush_warnings(struct dquot *const *dquots, char *warntype) | 1075 | static void flush_warnings(struct dquot *const *dquots, char *warntype) |
| 1147 | { | 1076 | { |
| 1077 | struct dquot *dq; | ||
| 1148 | int i; | 1078 | int i; |
| 1149 | 1079 | ||
| 1150 | for (i = 0; i < MAXQUOTAS; i++) | 1080 | for (i = 0; i < MAXQUOTAS; i++) { |
| 1151 | if (dquots[i] && warntype[i] != QUOTA_NL_NOWARN && | 1081 | dq = dquots[i]; |
| 1152 | !warning_issued(dquots[i], warntype[i])) { | 1082 | if (dq && warntype[i] != QUOTA_NL_NOWARN && |
| 1083 | !warning_issued(dq, warntype[i])) { | ||
| 1153 | #ifdef CONFIG_PRINT_QUOTA_WARNING | 1084 | #ifdef CONFIG_PRINT_QUOTA_WARNING |
| 1154 | print_warning(dquots[i], warntype[i]); | 1085 | print_warning(dq, warntype[i]); |
| 1155 | #endif | ||
| 1156 | #ifdef CONFIG_QUOTA_NETLINK_INTERFACE | ||
| 1157 | send_warning(dquots[i], warntype[i]); | ||
| 1158 | #endif | 1086 | #endif |
| 1087 | quota_send_warning(dq->dq_type, dq->dq_id, | ||
| 1088 | dq->dq_sb->s_dev, warntype[i]); | ||
| 1159 | } | 1089 | } |
| 1090 | } | ||
| 1160 | } | 1091 | } |
| 1161 | 1092 | ||
| 1162 | static int ignore_hardlimit(struct dquot *dquot) | 1093 | static int ignore_hardlimit(struct dquot *dquot) |
| @@ -2607,12 +2538,6 @@ static int __init dquot_init(void) | |||
| 2607 | 2538 | ||
| 2608 | register_shrinker(&dqcache_shrinker); | 2539 | register_shrinker(&dqcache_shrinker); |
| 2609 | 2540 | ||
| 2610 | #ifdef CONFIG_QUOTA_NETLINK_INTERFACE | ||
| 2611 | if (genl_register_family("a_genl_family) != 0) | ||
| 2612 | printk(KERN_ERR | ||
| 2613 | "VFS: Failed to create quota netlink interface.\n"); | ||
| 2614 | #endif | ||
| 2615 | |||
| 2616 | return 0; | 2541 | return 0; |
| 2617 | } | 2542 | } |
| 2618 | module_init(dquot_init); | 2543 | module_init(dquot_init); |
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 | |||
diff --git a/include/linux/quota.h b/include/linux/quota.h index 78c48895b12a..ce9a9b2e5cd4 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h | |||
| @@ -376,6 +376,17 @@ static inline unsigned int dquot_generic_flag(unsigned int flags, int type) | |||
| 376 | return flags >> _DQUOT_STATE_FLAGS; | 376 | return flags >> _DQUOT_STATE_FLAGS; |
| 377 | } | 377 | } |
| 378 | 378 | ||
| 379 | #ifdef CONFIG_QUOTA_NETLINK_INTERFACE | ||
| 380 | extern void quota_send_warning(short type, unsigned int id, dev_t dev, | ||
| 381 | const char warntype); | ||
| 382 | #else | ||
| 383 | static inline void quota_send_warning(short type, unsigned int id, dev_t dev, | ||
| 384 | const char warntype) | ||
| 385 | { | ||
| 386 | return; | ||
| 387 | } | ||
| 388 | #endif /* CONFIG_QUOTA_NETLINK_INTERFACE */ | ||
| 389 | |||
| 379 | struct quota_info { | 390 | struct quota_info { |
| 380 | unsigned int flags; /* Flags for diskquotas on this device */ | 391 | unsigned int flags; /* Flags for diskquotas on this device */ |
| 381 | struct mutex dqio_mutex; /* lock device while I/O in progress */ | 392 | struct mutex dqio_mutex; /* lock device while I/O in progress */ |
