aboutsummaryrefslogtreecommitdiffstats
path: root/fs
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 /fs
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>
Diffstat (limited to 'fs')
-rw-r--r--fs/Kconfig18
-rw-r--r--fs/dquot.c144
2 files changed, 132 insertions, 30 deletions
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);