aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dquot.c
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/dquot.c
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/dquot.c')
-rw-r--r--fs/dquot.c144
1 files changed, 114 insertions, 30 deletions
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);