aboutsummaryrefslogtreecommitdiffstats
path: root/fs/quota
diff options
context:
space:
mode:
Diffstat (limited to 'fs/quota')
-rw-r--r--fs/quota/Kconfig2
-rw-r--r--fs/quota/dquot.c128
-rw-r--r--fs/quota/quota.c93
3 files changed, 115 insertions, 108 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
18config QUOTA_NETLINK_INTERFACE 18config 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..eb5a755718f6 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 */
1077static 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 */
1086static 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 &quota_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;
1135attr_err_out:
1136 printk(KERN_ERR "VFS: Not enough space to compose quota message!\n");
1137err_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 */
1146static void flush_warnings(struct dquot *const *dquots, char *warntype) 1075static 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
1162static int ignore_hardlimit(struct dquot *dquot) 1093static int ignore_hardlimit(struct dquot *dquot)
@@ -2473,100 +2404,89 @@ const struct quotactl_ops vfs_quotactl_ops = {
2473 2404
2474static ctl_table fs_dqstats_table[] = { 2405static ctl_table fs_dqstats_table[] = {
2475 { 2406 {
2476 .ctl_name = FS_DQ_LOOKUPS,
2477 .procname = "lookups", 2407 .procname = "lookups",
2478 .data = &dqstats.lookups, 2408 .data = &dqstats.lookups,
2479 .maxlen = sizeof(int), 2409 .maxlen = sizeof(int),
2480 .mode = 0444, 2410 .mode = 0444,
2481 .proc_handler = &proc_dointvec, 2411 .proc_handler = proc_dointvec,
2482 }, 2412 },
2483 { 2413 {
2484 .ctl_name = FS_DQ_DROPS,
2485 .procname = "drops", 2414 .procname = "drops",
2486 .data = &dqstats.drops, 2415 .data = &dqstats.drops,
2487 .maxlen = sizeof(int), 2416 .maxlen = sizeof(int),
2488 .mode = 0444, 2417 .mode = 0444,
2489 .proc_handler = &proc_dointvec, 2418 .proc_handler = proc_dointvec,
2490 }, 2419 },
2491 { 2420 {
2492 .ctl_name = FS_DQ_READS,
2493 .procname = "reads", 2421 .procname = "reads",
2494 .data = &dqstats.reads, 2422 .data = &dqstats.reads,
2495 .maxlen = sizeof(int), 2423 .maxlen = sizeof(int),
2496 .mode = 0444, 2424 .mode = 0444,
2497 .proc_handler = &proc_dointvec, 2425 .proc_handler = proc_dointvec,
2498 }, 2426 },
2499 { 2427 {
2500 .ctl_name = FS_DQ_WRITES,
2501 .procname = "writes", 2428 .procname = "writes",
2502 .data = &dqstats.writes, 2429 .data = &dqstats.writes,
2503 .maxlen = sizeof(int), 2430 .maxlen = sizeof(int),
2504 .mode = 0444, 2431 .mode = 0444,
2505 .proc_handler = &proc_dointvec, 2432 .proc_handler = proc_dointvec,
2506 }, 2433 },
2507 { 2434 {
2508 .ctl_name = FS_DQ_CACHE_HITS,
2509 .procname = "cache_hits", 2435 .procname = "cache_hits",
2510 .data = &dqstats.cache_hits, 2436 .data = &dqstats.cache_hits,
2511 .maxlen = sizeof(int), 2437 .maxlen = sizeof(int),
2512 .mode = 0444, 2438 .mode = 0444,
2513 .proc_handler = &proc_dointvec, 2439 .proc_handler = proc_dointvec,
2514 }, 2440 },
2515 { 2441 {
2516 .ctl_name = FS_DQ_ALLOCATED,
2517 .procname = "allocated_dquots", 2442 .procname = "allocated_dquots",
2518 .data = &dqstats.allocated_dquots, 2443 .data = &dqstats.allocated_dquots,
2519 .maxlen = sizeof(int), 2444 .maxlen = sizeof(int),
2520 .mode = 0444, 2445 .mode = 0444,
2521 .proc_handler = &proc_dointvec, 2446 .proc_handler = proc_dointvec,
2522 }, 2447 },
2523 { 2448 {
2524 .ctl_name = FS_DQ_FREE,
2525 .procname = "free_dquots", 2449 .procname = "free_dquots",
2526 .data = &dqstats.free_dquots, 2450 .data = &dqstats.free_dquots,
2527 .maxlen = sizeof(int), 2451 .maxlen = sizeof(int),
2528 .mode = 0444, 2452 .mode = 0444,
2529 .proc_handler = &proc_dointvec, 2453 .proc_handler = proc_dointvec,
2530 }, 2454 },
2531 { 2455 {
2532 .ctl_name = FS_DQ_SYNCS,
2533 .procname = "syncs", 2456 .procname = "syncs",
2534 .data = &dqstats.syncs, 2457 .data = &dqstats.syncs,
2535 .maxlen = sizeof(int), 2458 .maxlen = sizeof(int),
2536 .mode = 0444, 2459 .mode = 0444,
2537 .proc_handler = &proc_dointvec, 2460 .proc_handler = proc_dointvec,
2538 }, 2461 },
2539#ifdef CONFIG_PRINT_QUOTA_WARNING 2462#ifdef CONFIG_PRINT_QUOTA_WARNING
2540 { 2463 {
2541 .ctl_name = FS_DQ_WARNINGS,
2542 .procname = "warnings", 2464 .procname = "warnings",
2543 .data = &flag_print_warnings, 2465 .data = &flag_print_warnings,
2544 .maxlen = sizeof(int), 2466 .maxlen = sizeof(int),
2545 .mode = 0644, 2467 .mode = 0644,
2546 .proc_handler = &proc_dointvec, 2468 .proc_handler = proc_dointvec,
2547 }, 2469 },
2548#endif 2470#endif
2549 { .ctl_name = 0 }, 2471 { },
2550}; 2472};
2551 2473
2552static ctl_table fs_table[] = { 2474static ctl_table fs_table[] = {
2553 { 2475 {
2554 .ctl_name = FS_DQSTATS,
2555 .procname = "quota", 2476 .procname = "quota",
2556 .mode = 0555, 2477 .mode = 0555,
2557 .child = fs_dqstats_table, 2478 .child = fs_dqstats_table,
2558 }, 2479 },
2559 { .ctl_name = 0 }, 2480 { },
2560}; 2481};
2561 2482
2562static ctl_table sys_table[] = { 2483static ctl_table sys_table[] = {
2563 { 2484 {
2564 .ctl_name = CTL_FS,
2565 .procname = "fs", 2485 .procname = "fs",
2566 .mode = 0555, 2486 .mode = 0555,
2567 .child = fs_table, 2487 .child = fs_table,
2568 }, 2488 },
2569 { .ctl_name = 0 }, 2489 { },
2570}; 2490};
2571 2491
2572static int __init dquot_init(void) 2492static int __init dquot_init(void)
@@ -2607,12 +2527,6 @@ static int __init dquot_init(void)
2607 2527
2608 register_shrinker(&dqcache_shrinker); 2528 register_shrinker(&dqcache_shrinker);
2609 2529
2610#ifdef CONFIG_QUOTA_NETLINK_INTERFACE
2611 if (genl_register_family(&quota_genl_family) != 0)
2612 printk(KERN_ERR
2613 "VFS: Failed to create quota netlink interface.\n");
2614#endif
2615
2616 return 0; 2530 return 0;
2617} 2531}
2618module_init(dquot_init); 2532module_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 */
23static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, 25static 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 */
535static 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
555void 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 &quota_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;
603attr_err_out:
604 printk(KERN_ERR "VFS: Not enough space to compose quota message!\n");
605err_out:
606 kfree_skb(skb);
607}
608EXPORT_SYMBOL(quota_send_warning);
609
610static int __init quota_init(void)
611{
612 if (genl_register_family(&quota_genl_family) != 0)
613 printk(KERN_ERR
614 "VFS: Failed to create quota netlink interface.\n");
615 return 0;
616};
617
618module_init(quota_init);
619#endif
620