aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2007-10-17 02:29:31 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-17 11:42:56 -0400
commit8e8934695dfd1d5013555a74a9da706a2e301cb0 (patch)
treeedef65302982cbd3e18cf4ef3c88040939886e3a
parentfac8b209b1084bc85748bd54e13d00c1262b220f (diff)
quota: send messages via netlink
Implement sending of quota messages via netlink interface. The advantage is that in userspace we can better decide what to do with the message - for example display a dialogue in your X session or just write the message to the console. As a bonus, we can get rid of problems with console locking deep inside filesystem code once we remove the old printing mechanism. Signed-off-by: Jan Kara <jack@suse.cz> Cc: Randy Dunlap <randy.dunlap@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--Documentation/filesystems/quota.txt59
-rw-r--r--fs/Kconfig18
-rw-r--r--fs/dquot.c144
-rw-r--r--include/linux/quota.h31
4 files changed, 222 insertions, 30 deletions
diff --git a/Documentation/filesystems/quota.txt b/Documentation/filesystems/quota.txt
new file mode 100644
index 000000000000..a590c4093eff
--- /dev/null
+++ b/Documentation/filesystems/quota.txt
@@ -0,0 +1,59 @@
1
2Quota subsystem
3===============
4
5Quota subsystem allows system administrator to set limits on used space and
6number of used inodes (inode is a filesystem structure which is associated
7with each file or directory) for users and/or groups. For both used space and
8number of used inodes there are actually two limits. The first one is called
9softlimit and the second one hardlimit. An user can never exceed a hardlimit
10for any resource. User is allowed to exceed softlimit but only for limited
11period of time. This period is called "grace period" or "grace time". When
12grace time is over, user is not able to allocate more space/inodes until he
13frees enough of them to get below softlimit.
14
15Quota limits (and amount of grace time) are set independently for each
16filesystem.
17
18For more details about quota design, see the documentation in quota-tools package
19(http://sourceforge.net/projects/linuxquota).
20
21Quota netlink interface
22=======================
23When user exceeds a softlimit, runs out of grace time or reaches hardlimit,
24quota subsystem traditionally printed a message to the controlling terminal of
25the process which caused the excess. This method has the disadvantage that
26when user is using a graphical desktop he usually cannot see the message.
27Thus quota netlink interface has been designed to pass information about
28the above events to userspace. There they can be captured by an application
29and processed accordingly.
30
31The interface uses generic netlink framework (see
32http://lwn.net/Articles/208755/ and http://people.suug.ch/~tgr/libnl/ for more
33details about this layer). The name of the quota generic netlink interface
34is "VFS_DQUOT". Definitions of constants below are in <linux/quota.h>.
35 Currently, the interface supports only one message type QUOTA_NL_C_WARNING.
36This command is used to send a notification about any of the above mentioned
37events. Each message has six attributes. These are (type of the argument is
38in parentheses):
39 QUOTA_NL_A_QTYPE (u32)
40 - type of quota being exceeded (one of USRQUOTA, GRPQUOTA)
41 QUOTA_NL_A_EXCESS_ID (u64)
42 - UID/GID (depends on quota type) of user / group whose limit
43 is being exceeded.
44 QUOTA_NL_A_CAUSED_ID (u64)
45 - UID of a user who caused the event
46 QUOTA_NL_A_WARNING (u32)
47 - what kind of limit is exceeded:
48 QUOTA_NL_IHARDWARN - inode hardlimit
49 QUOTA_NL_ISOFTLONGWARN - inode softlimit is exceeded longer
50 than given grace period
51 QUOTA_NL_ISOFTWARN - inode softlimit
52 QUOTA_NL_BHARDWARN - space (block) hardlimit
53 QUOTA_NL_BSOFTLONGWARN - space (block) softlimit is exceeded
54 longer than given grace period.
55 QUOTA_NL_BSOFTWARN - space (block) softlimit
56 QUOTA_NL_A_DEV_MAJOR (u32)
57 - major number of a device with the affected filesystem
58 QUOTA_NL_A_DEV_MINOR (u32)
59 - minor number of a device with the affected filesystem
diff --git a/fs/Kconfig b/fs/Kconfig
index f0df9a2e19e1..dc06033f8502 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -534,6 +534,24 @@ config QUOTA
534 with the quota tools. Probably the quota support is only useful for 534 with the quota tools. Probably the quota support is only useful for
535 multi user systems. If unsure, say N. 535 multi user systems. If unsure, say N.
536 536
537config QUOTA_NETLINK_INTERFACE
538 bool "Report quota messages through netlink interface"
539 depends on QUOTA && NET
540 help
541 If you say Y here, quota warnings (about exceeding softlimit, reaching
542 hardlimit, etc.) will be reported through netlink interface. If unsure,
543 say Y.
544
545config PRINT_QUOTA_WARNING
546 bool "Print quota warnings to console (OBSOLETE)"
547 depends on QUOTA
548 default y
549 help
550 If you say Y here, quota warnings (about exceeding softlimit, reaching
551 hardlimit, etc.) will be printed to the process' controlling terminal.
552 Note that this behavior is currently deprecated and may go away in
553 future. Please use notification via netlink socket instead.
554
537config QFMT_V1 555config QFMT_V1
538 tristate "Old quota format support" 556 tristate "Old quota format support"
539 depends on QUOTA 557 depends on QUOTA
diff --git a/fs/dquot.c b/fs/dquot.c
index de9a29f64ff3..2809768d9c41 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -79,6 +79,10 @@
79#include <linux/capability.h> 79#include <linux/capability.h>
80#include <linux/quotaops.h> 80#include <linux/quotaops.h>
81#include <linux/writeback.h> /* for inode_lock, oddly enough.. */ 81#include <linux/writeback.h> /* for inode_lock, oddly enough.. */
82#ifdef CONFIG_QUOTA_NETLINK_INTERFACE
83#include <net/netlink.h>
84#include <net/genetlink.h>
85#endif
82 86
83#include <asm/uaccess.h> 87#include <asm/uaccess.h>
84 88
@@ -823,6 +827,7 @@ static inline void dquot_decr_space(struct dquot *dquot, qsize_t number)
823 clear_bit(DQ_BLKS_B, &dquot->dq_flags); 827 clear_bit(DQ_BLKS_B, &dquot->dq_flags);
824} 828}
825 829
830#ifdef CONFIG_PRINT_QUOTA_WARNING
826static int flag_print_warnings = 1; 831static int flag_print_warnings = 1;
827 832
828static inline int need_print_warning(struct dquot *dquot) 833static inline int need_print_warning(struct dquot *dquot)
@@ -839,22 +844,15 @@ static inline int need_print_warning(struct dquot *dquot)
839 return 0; 844 return 0;
840} 845}
841 846
842/* Values of warnings */
843#define NOWARN 0
844#define IHARDWARN 1
845#define ISOFTLONGWARN 2
846#define ISOFTWARN 3
847#define BHARDWARN 4
848#define BSOFTLONGWARN 5
849#define BSOFTWARN 6
850
851/* Print warning to user which exceeded quota */ 847/* Print warning to user which exceeded quota */
852static void print_warning(struct dquot *dquot, const char warntype) 848static void print_warning(struct dquot *dquot, const char warntype)
853{ 849{
854 char *msg = NULL; 850 char *msg = NULL;
855 struct tty_struct *tty; 851 struct tty_struct *tty;
856 int flag = (warntype == BHARDWARN || warntype == BSOFTLONGWARN) ? DQ_BLKS_B : 852 int flag = (warntype == QUOTA_NL_BHARDWARN ||
857 ((warntype == IHARDWARN || warntype == ISOFTLONGWARN) ? DQ_INODES_B : 0); 853 warntype == QUOTA_NL_BSOFTLONGWARN) ? DQ_BLKS_B :
854 ((warntype == QUOTA_NL_IHARDWARN ||
855 warntype == QUOTA_NL_ISOFTLONGWARN) ? DQ_INODES_B : 0);
858 856
859 if (!need_print_warning(dquot) || (flag && test_and_set_bit(flag, &dquot->dq_flags))) 857 if (!need_print_warning(dquot) || (flag && test_and_set_bit(flag, &dquot->dq_flags)))
860 return; 858 return;
@@ -864,28 +862,28 @@ static void print_warning(struct dquot *dquot, const char warntype)
864 if (!tty) 862 if (!tty)
865 goto out_lock; 863 goto out_lock;
866 tty_write_message(tty, dquot->dq_sb->s_id); 864 tty_write_message(tty, dquot->dq_sb->s_id);
867 if (warntype == ISOFTWARN || warntype == BSOFTWARN) 865 if (warntype == QUOTA_NL_ISOFTWARN || warntype == QUOTA_NL_BSOFTWARN)
868 tty_write_message(tty, ": warning, "); 866 tty_write_message(tty, ": warning, ");
869 else 867 else
870 tty_write_message(tty, ": write failed, "); 868 tty_write_message(tty, ": write failed, ");
871 tty_write_message(tty, quotatypes[dquot->dq_type]); 869 tty_write_message(tty, quotatypes[dquot->dq_type]);
872 switch (warntype) { 870 switch (warntype) {
873 case IHARDWARN: 871 case QUOTA_NL_IHARDWARN:
874 msg = " file limit reached.\r\n"; 872 msg = " file limit reached.\r\n";
875 break; 873 break;
876 case ISOFTLONGWARN: 874 case QUOTA_NL_ISOFTLONGWARN:
877 msg = " file quota exceeded too long.\r\n"; 875 msg = " file quota exceeded too long.\r\n";
878 break; 876 break;
879 case ISOFTWARN: 877 case QUOTA_NL_ISOFTWARN:
880 msg = " file quota exceeded.\r\n"; 878 msg = " file quota exceeded.\r\n";
881 break; 879 break;
882 case BHARDWARN: 880 case QUOTA_NL_BHARDWARN:
883 msg = " block limit reached.\r\n"; 881 msg = " block limit reached.\r\n";
884 break; 882 break;
885 case BSOFTLONGWARN: 883 case QUOTA_NL_BSOFTLONGWARN:
886 msg = " block quota exceeded too long.\r\n"; 884 msg = " block quota exceeded too long.\r\n";
887 break; 885 break;
888 case BSOFTWARN: 886 case QUOTA_NL_BSOFTWARN:
889 msg = " block quota exceeded.\r\n"; 887 msg = " block quota exceeded.\r\n";
890 break; 888 break;
891 } 889 }
@@ -893,14 +891,93 @@ static void print_warning(struct dquot *dquot, const char warntype)
893out_lock: 891out_lock:
894 mutex_unlock(&tty_mutex); 892 mutex_unlock(&tty_mutex);
895} 893}
894#endif
895
896#ifdef CONFIG_QUOTA_NETLINK_INTERFACE
897
898/* Size of quota netlink message - actually an upperbound for buffer size */
899#define QUOTA_NL_MSG_SIZE 32
900
901/* Netlink family structure for quota */
902static struct genl_family quota_genl_family = {
903 .id = GENL_ID_GENERATE,
904 .hdrsize = 0,
905 .name = "VFS_DQUOT",
906 .version = 1,
907 .maxattr = QUOTA_NL_A_MAX,
908};
909
910/* Send warning to userspace about user which exceeded quota */
911static void send_warning(const struct dquot *dquot, const char warntype)
912{
913 static atomic_t seq;
914 struct sk_buff *skb;
915 void *msg_head;
916 int ret;
917
918 /* We have to allocate using GFP_NOFS as we are called from a
919 * filesystem performing write and thus further recursion into
920 * the fs to free some data could cause deadlocks. */
921 skb = genlmsg_new(QUOTA_NL_MSG_SIZE, GFP_NOFS);
922 if (!skb) {
923 printk(KERN_ERR
924 "VFS: Not enough memory to send quota warning.\n");
925 return;
926 }
927 msg_head = genlmsg_put(skb, 0, atomic_add_return(1, &seq),
928 &quota_genl_family, 0, QUOTA_NL_C_WARNING);
929 if (!msg_head) {
930 printk(KERN_ERR
931 "VFS: Cannot store netlink header in quota warning.\n");
932 goto err_out;
933 }
934 ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, dquot->dq_type);
935 if (ret)
936 goto attr_err_out;
937 ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, dquot->dq_id);
938 if (ret)
939 goto attr_err_out;
940 ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype);
941 if (ret)
942 goto attr_err_out;
943 ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MAJOR,
944 MAJOR(dquot->dq_sb->s_dev));
945 if (ret)
946 goto attr_err_out;
947 ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR,
948 MINOR(dquot->dq_sb->s_dev));
949 if (ret)
950 goto attr_err_out;
951 ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current->user->uid);
952 if (ret)
953 goto attr_err_out;
954 genlmsg_end(skb, msg_head);
955
956 ret = genlmsg_multicast(skb, 0, quota_genl_family.id, GFP_NOFS);
957 if (ret < 0 && ret != -ESRCH)
958 printk(KERN_ERR
959 "VFS: Failed to send notification message: %d\n", ret);
960 return;
961attr_err_out:
962 printk(KERN_ERR "VFS: Failed to compose quota message: %d\n", ret);
963err_out:
964 kfree_skb(skb);
965}
966#endif
896 967
897static inline void flush_warnings(struct dquot **dquots, char *warntype) 968static inline void flush_warnings(struct dquot **dquots, char *warntype)
898{ 969{
899 int i; 970 int i;
900 971
901 for (i = 0; i < MAXQUOTAS; i++) 972 for (i = 0; i < MAXQUOTAS; i++)
902 if (dquots[i] != NODQUOT && warntype[i] != NOWARN) 973 if (dquots[i] != NODQUOT && warntype[i] != QUOTA_NL_NOWARN) {
974#ifdef CONFIG_PRINT_QUOTA_WARNING
903 print_warning(dquots[i], warntype[i]); 975 print_warning(dquots[i], warntype[i]);
976#endif
977#ifdef CONFIG_QUOTA_NETLINK_INTERFACE
978 send_warning(dquots[i], warntype[i]);
979#endif
980 }
904} 981}
905 982
906static inline char ignore_hardlimit(struct dquot *dquot) 983static inline char ignore_hardlimit(struct dquot *dquot)
@@ -914,14 +991,14 @@ static inline char ignore_hardlimit(struct dquot *dquot)
914/* needs dq_data_lock */ 991/* needs dq_data_lock */
915static int check_idq(struct dquot *dquot, ulong inodes, char *warntype) 992static int check_idq(struct dquot *dquot, ulong inodes, char *warntype)
916{ 993{
917 *warntype = NOWARN; 994 *warntype = QUOTA_NL_NOWARN;
918 if (inodes <= 0 || test_bit(DQ_FAKE_B, &dquot->dq_flags)) 995 if (inodes <= 0 || test_bit(DQ_FAKE_B, &dquot->dq_flags))
919 return QUOTA_OK; 996 return QUOTA_OK;
920 997
921 if (dquot->dq_dqb.dqb_ihardlimit && 998 if (dquot->dq_dqb.dqb_ihardlimit &&
922 (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_ihardlimit && 999 (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_ihardlimit &&
923 !ignore_hardlimit(dquot)) { 1000 !ignore_hardlimit(dquot)) {
924 *warntype = IHARDWARN; 1001 *warntype = QUOTA_NL_IHARDWARN;
925 return NO_QUOTA; 1002 return NO_QUOTA;
926 } 1003 }
927 1004
@@ -929,14 +1006,14 @@ static int check_idq(struct dquot *dquot, ulong inodes, char *warntype)
929 (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_isoftlimit && 1006 (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_isoftlimit &&
930 dquot->dq_dqb.dqb_itime && get_seconds() >= dquot->dq_dqb.dqb_itime && 1007 dquot->dq_dqb.dqb_itime && get_seconds() >= dquot->dq_dqb.dqb_itime &&
931 !ignore_hardlimit(dquot)) { 1008 !ignore_hardlimit(dquot)) {
932 *warntype = ISOFTLONGWARN; 1009 *warntype = QUOTA_NL_ISOFTLONGWARN;
933 return NO_QUOTA; 1010 return NO_QUOTA;
934 } 1011 }
935 1012
936 if (dquot->dq_dqb.dqb_isoftlimit && 1013 if (dquot->dq_dqb.dqb_isoftlimit &&
937 (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_isoftlimit && 1014 (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_isoftlimit &&
938 dquot->dq_dqb.dqb_itime == 0) { 1015 dquot->dq_dqb.dqb_itime == 0) {
939 *warntype = ISOFTWARN; 1016 *warntype = QUOTA_NL_ISOFTWARN;
940 dquot->dq_dqb.dqb_itime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace; 1017 dquot->dq_dqb.dqb_itime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
941 } 1018 }
942 1019
@@ -946,7 +1023,7 @@ static int check_idq(struct dquot *dquot, ulong inodes, char *warntype)
946/* needs dq_data_lock */ 1023/* needs dq_data_lock */
947static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype) 1024static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype)
948{ 1025{
949 *warntype = 0; 1026 *warntype = QUOTA_NL_NOWARN;
950 if (space <= 0 || test_bit(DQ_FAKE_B, &dquot->dq_flags)) 1027 if (space <= 0 || test_bit(DQ_FAKE_B, &dquot->dq_flags))
951 return QUOTA_OK; 1028 return QUOTA_OK;
952 1029
@@ -954,7 +1031,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war
954 toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bhardlimit && 1031 toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bhardlimit &&
955 !ignore_hardlimit(dquot)) { 1032 !ignore_hardlimit(dquot)) {
956 if (!prealloc) 1033 if (!prealloc)
957 *warntype = BHARDWARN; 1034 *warntype = QUOTA_NL_BHARDWARN;
958 return NO_QUOTA; 1035 return NO_QUOTA;
959 } 1036 }
960 1037
@@ -963,7 +1040,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war
963 dquot->dq_dqb.dqb_btime && get_seconds() >= dquot->dq_dqb.dqb_btime && 1040 dquot->dq_dqb.dqb_btime && get_seconds() >= dquot->dq_dqb.dqb_btime &&
964 !ignore_hardlimit(dquot)) { 1041 !ignore_hardlimit(dquot)) {
965 if (!prealloc) 1042 if (!prealloc)
966 *warntype = BSOFTLONGWARN; 1043 *warntype = QUOTA_NL_BSOFTLONGWARN;
967 return NO_QUOTA; 1044 return NO_QUOTA;
968 } 1045 }
969 1046
@@ -971,7 +1048,7 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war
971 toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bsoftlimit && 1048 toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bsoftlimit &&
972 dquot->dq_dqb.dqb_btime == 0) { 1049 dquot->dq_dqb.dqb_btime == 0) {
973 if (!prealloc) { 1050 if (!prealloc) {
974 *warntype = BSOFTWARN; 1051 *warntype = QUOTA_NL_BSOFTWARN;
975 dquot->dq_dqb.dqb_btime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace; 1052 dquot->dq_dqb.dqb_btime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace;
976 } 1053 }
977 else 1054 else
@@ -1066,7 +1143,7 @@ out_add:
1066 return QUOTA_OK; 1143 return QUOTA_OK;
1067 } 1144 }
1068 for (cnt = 0; cnt < MAXQUOTAS; cnt++) 1145 for (cnt = 0; cnt < MAXQUOTAS; cnt++)
1069 warntype[cnt] = NOWARN; 1146 warntype[cnt] = QUOTA_NL_NOWARN;
1070 1147
1071 down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); 1148 down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
1072 if (IS_NOQUOTA(inode)) { /* Now we can do reliable test... */ 1149 if (IS_NOQUOTA(inode)) { /* Now we can do reliable test... */
@@ -1112,7 +1189,7 @@ int dquot_alloc_inode(const struct inode *inode, unsigned long number)
1112 if (IS_NOQUOTA(inode)) 1189 if (IS_NOQUOTA(inode))
1113 return QUOTA_OK; 1190 return QUOTA_OK;
1114 for (cnt = 0; cnt < MAXQUOTAS; cnt++) 1191 for (cnt = 0; cnt < MAXQUOTAS; cnt++)
1115 warntype[cnt] = NOWARN; 1192 warntype[cnt] = QUOTA_NL_NOWARN;
1116 down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); 1193 down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
1117 if (IS_NOQUOTA(inode)) { 1194 if (IS_NOQUOTA(inode)) {
1118 up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); 1195 up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
@@ -1234,7 +1311,7 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
1234 /* Clear the arrays */ 1311 /* Clear the arrays */
1235 for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 1312 for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
1236 transfer_to[cnt] = transfer_from[cnt] = NODQUOT; 1313 transfer_to[cnt] = transfer_from[cnt] = NODQUOT;
1237 warntype[cnt] = NOWARN; 1314 warntype[cnt] = QUOTA_NL_NOWARN;
1238 } 1315 }
1239 down_write(&sb_dqopt(inode->i_sb)->dqptr_sem); 1316 down_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
1240 /* Now recheck reliably when holding dqptr_sem */ 1317 /* Now recheck reliably when holding dqptr_sem */
@@ -1808,6 +1885,7 @@ static ctl_table fs_dqstats_table[] = {
1808 .mode = 0444, 1885 .mode = 0444,
1809 .proc_handler = &proc_dointvec, 1886 .proc_handler = &proc_dointvec,
1810 }, 1887 },
1888#ifdef CONFIG_PRINT_QUOTA_WARNING
1811 { 1889 {
1812 .ctl_name = FS_DQ_WARNINGS, 1890 .ctl_name = FS_DQ_WARNINGS,
1813 .procname = "warnings", 1891 .procname = "warnings",
@@ -1816,6 +1894,7 @@ static ctl_table fs_dqstats_table[] = {
1816 .mode = 0644, 1894 .mode = 0644,
1817 .proc_handler = &proc_dointvec, 1895 .proc_handler = &proc_dointvec,
1818 }, 1896 },
1897#endif
1819 { .ctl_name = 0 }, 1898 { .ctl_name = 0 },
1820}; 1899};
1821 1900
@@ -1877,6 +1956,11 @@ static int __init dquot_init(void)
1877 1956
1878 register_shrinker(&dqcache_shrinker); 1957 register_shrinker(&dqcache_shrinker);
1879 1958
1959#ifdef CONFIG_QUOTA_NETLINK_INTERFACE
1960 if (genl_register_family(&quota_genl_family) != 0)
1961 printk(KERN_ERR "VFS: Failed to create quota netlink interface.\n");
1962#endif
1963
1880 return 0; 1964 return 0;
1881} 1965}
1882module_init(dquot_init); 1966module_init(dquot_init);
diff --git a/include/linux/quota.h b/include/linux/quota.h
index 62439828395e..6e0393a5b2ea 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -128,6 +128,37 @@ struct if_dqinfo {
128 __u32 dqi_valid; 128 __u32 dqi_valid;
129}; 129};
130 130
131/*
132 * Definitions for quota netlink interface
133 */
134#define QUOTA_NL_NOWARN 0
135#define QUOTA_NL_IHARDWARN 1 /* Inode hardlimit reached */
136#define QUOTA_NL_ISOFTLONGWARN 2 /* Inode grace time expired */
137#define QUOTA_NL_ISOFTWARN 3 /* Inode softlimit reached */
138#define QUOTA_NL_BHARDWARN 4 /* Block hardlimit reached */
139#define QUOTA_NL_BSOFTLONGWARN 5 /* Block grace time expired */
140#define QUOTA_NL_BSOFTWARN 6 /* Block softlimit reached */
141
142enum {
143 QUOTA_NL_C_UNSPEC,
144 QUOTA_NL_C_WARNING,
145 __QUOTA_NL_C_MAX,
146};
147#define QUOTA_NL_C_MAX (__QUOTA_NL_C_MAX - 1)
148
149enum {
150 QUOTA_NL_A_UNSPEC,
151 QUOTA_NL_A_QTYPE,
152 QUOTA_NL_A_EXCESS_ID,
153 QUOTA_NL_A_WARNING,
154 QUOTA_NL_A_DEV_MAJOR,
155 QUOTA_NL_A_DEV_MINOR,
156 QUOTA_NL_A_CAUSED_ID,
157 __QUOTA_NL_A_MAX,
158};
159#define QUOTA_NL_A_MAX (__QUOTA_NL_A_MAX - 1)
160
161
131#ifdef __KERNEL__ 162#ifdef __KERNEL__
132#include <linux/spinlock.h> 163#include <linux/spinlock.h>
133#include <linux/rwsem.h> 164#include <linux/rwsem.h>