diff options
author | Jan Kara <jack@suse.cz> | 2007-10-17 02:29:31 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-17 11:42:56 -0400 |
commit | 8e8934695dfd1d5013555a74a9da706a2e301cb0 (patch) | |
tree | edef65302982cbd3e18cf4ef3c88040939886e3a | |
parent | fac8b209b1084bc85748bd54e13d00c1262b220f (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.txt | 59 | ||||
-rw-r--r-- | fs/Kconfig | 18 | ||||
-rw-r--r-- | fs/dquot.c | 144 | ||||
-rw-r--r-- | include/linux/quota.h | 31 |
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 | |||
2 | Quota subsystem | ||
3 | =============== | ||
4 | |||
5 | Quota subsystem allows system administrator to set limits on used space and | ||
6 | number of used inodes (inode is a filesystem structure which is associated | ||
7 | with each file or directory) for users and/or groups. For both used space and | ||
8 | number of used inodes there are actually two limits. The first one is called | ||
9 | softlimit and the second one hardlimit. An user can never exceed a hardlimit | ||
10 | for any resource. User is allowed to exceed softlimit but only for limited | ||
11 | period of time. This period is called "grace period" or "grace time". When | ||
12 | grace time is over, user is not able to allocate more space/inodes until he | ||
13 | frees enough of them to get below softlimit. | ||
14 | |||
15 | Quota limits (and amount of grace time) are set independently for each | ||
16 | filesystem. | ||
17 | |||
18 | For more details about quota design, see the documentation in quota-tools package | ||
19 | (http://sourceforge.net/projects/linuxquota). | ||
20 | |||
21 | Quota netlink interface | ||
22 | ======================= | ||
23 | When user exceeds a softlimit, runs out of grace time or reaches hardlimit, | ||
24 | quota subsystem traditionally printed a message to the controlling terminal of | ||
25 | the process which caused the excess. This method has the disadvantage that | ||
26 | when user is using a graphical desktop he usually cannot see the message. | ||
27 | Thus quota netlink interface has been designed to pass information about | ||
28 | the above events to userspace. There they can be captured by an application | ||
29 | and processed accordingly. | ||
30 | |||
31 | The interface uses generic netlink framework (see | ||
32 | http://lwn.net/Articles/208755/ and http://people.suug.ch/~tgr/libnl/ for more | ||
33 | details about this layer). The name of the quota generic netlink interface | ||
34 | is "VFS_DQUOT". Definitions of constants below are in <linux/quota.h>. | ||
35 | Currently, the interface supports only one message type QUOTA_NL_C_WARNING. | ||
36 | This command is used to send a notification about any of the above mentioned | ||
37 | events. Each message has six attributes. These are (type of the argument is | ||
38 | in 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 | ||
537 | config 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 | |||
545 | config 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 | |||
537 | config QFMT_V1 | 555 | config 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 | ||
826 | static int flag_print_warnings = 1; | 831 | static int flag_print_warnings = 1; |
827 | 832 | ||
828 | static inline int need_print_warning(struct dquot *dquot) | 833 | static 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 */ |
852 | static void print_warning(struct dquot *dquot, const char warntype) | 848 | static 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) | |||
893 | out_lock: | 891 | out_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 */ | ||
902 | static 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 */ | ||
911 | static 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 | "a_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; | ||
961 | attr_err_out: | ||
962 | printk(KERN_ERR "VFS: Failed to compose quota message: %d\n", ret); | ||
963 | err_out: | ||
964 | kfree_skb(skb); | ||
965 | } | ||
966 | #endif | ||
896 | 967 | ||
897 | static inline void flush_warnings(struct dquot **dquots, char *warntype) | 968 | static 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 | ||
906 | static inline char ignore_hardlimit(struct dquot *dquot) | 983 | static 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 */ |
915 | static int check_idq(struct dquot *dquot, ulong inodes, char *warntype) | 992 | static 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 */ |
947 | static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype) | 1024 | static 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("a_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 | } |
1882 | module_init(dquot_init); | 1966 | module_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 | |||
142 | enum { | ||
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 | |||
149 | enum { | ||
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> |