lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAPTn0cAOeQ_nyKx5k+kJOzx17tq+5WtyrMhBE8bpFCKx0UecGw@mail.gmail.com>
Date:	Wed, 10 Sep 2014 11:52:35 +0800
From:	Li Xi <pkuelelixi@...il.com>
To:	"linux-fsdevel@...r.kernel.org" <linux-fsdevel@...r.kernel.org>,
	Ext4 Developers List <linux-ext4@...r.kernel.org>,
	"Theodore Ts'o" <tytso@....edu>,
	Andreas Dilger <adilger@...ger.ca>,
	"viro@...iv.linux.org.uk" <viro@...iv.linux.org.uk>,
	"hch@...radead.org" <hch@...radead.org>, Jan Kara <jack@...e.cz>,
	Dmitry Monakhov <dmonakhov@...nvz.org>
Subject: [PATCH v3 1/4] quota: add project quota support

Adds general codes to enforces project quota limits

This patch adds support for a new quota type PRJQUOTA for project quota
enforcement. Also a new method get_projid() is added into dquot_operations
structure.

Signed-off-by: Li Xi <lixi <at> ddn.com>
Signed-off-by: Dmitry Monakhov <dmonakhov@...nvz.org>
---
Index: linux.git/fs/quota/dquot.c
===================================================================
--- linux.git.orig/fs/quota/dquot.c
+++ linux.git/fs/quota/dquot.c
@@ -161,6 +161,19 @@ static struct quota_module_name module_n
 /* SLAB cache for dquot structures */
 static struct kmem_cache *dquot_cachep;

+static inline unsigned long compat_qtype2bits(int type)
+{
+#ifdef CONFIG_QUOTA_PROJECT
+    unsigned long qtype_bits = QUOTA_ALL_BIT;
+#else
+    unsigned long qtype_bits = QUOTA_USR_BIT | QUOTA_GRP_BIT;
+#endif
+    if (type != -1) {
+        qtype_bits = 1 << type;
+    }
+    return qtype_bits;
+}
+
 int register_quota_format(struct quota_format_type *fmt)
 {
     spin_lock(&dq_list_lock);
@@ -250,7 +263,8 @@ struct dqstats dqstats;
 EXPORT_SYMBOL(dqstats);

 static qsize_t inode_get_rsv_space(struct inode *inode);
-static void __dquot_initialize(struct inode *inode, int type);
+static void __dquot_initialize(struct inode *inode,
+                   unsigned long qtype_bits);

 static inline unsigned int
 hashfn(const struct super_block *sb, struct kqid qid)
@@ -513,7 +527,8 @@ static inline void do_destroy_dquot(stru
  * just deleted or pruned by prune_icache() (those are not attached to any
  * list) or parallel quotactl call. We have to wait for such users.
  */
-static void invalidate_dquots(struct super_block *sb, int type)
+static void invalidate_dquots(struct super_block *sb,
+                  unsigned long qtype_bits)
 {
     struct dquot *dquot, *tmp;

@@ -522,7 +537,7 @@ restart:
     list_for_each_entry_safe(dquot, tmp, &inuse_list, dq_inuse) {
         if (dquot->dq_sb != sb)
             continue;
-        if (dquot->dq_id.type != type)
+        if (((1 << dquot->dq_id.type) & qtype_bits) == 0)
             continue;
         /* Wait for dquot users */
         if (atomic_read(&dquot->dq_count)) {
@@ -605,7 +620,8 @@ out:
 EXPORT_SYMBOL(dquot_scan_active);

 /* Write all dquot structures to quota files */
-int dquot_writeback_dquots(struct super_block *sb, int type)
+static int __dquot_writeback_dquots(struct super_block *sb,
+                    unsigned long qtype_bits)
 {
     struct list_head *dirty;
     struct dquot *dquot;
@@ -615,7 +631,7 @@ int dquot_writeback_dquots(struct super_

     mutex_lock(&dqopt->dqonoff_mutex);
     for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-        if (type != -1 && cnt != type)
+        if (((1 << cnt) & qtype_bits) == 0)
             continue;
         if (!sb_has_quota_active(sb, cnt))
             continue;
@@ -645,7 +661,7 @@ int dquot_writeback_dquots(struct super_
     }

     for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-        if ((cnt == type || type == -1) && sb_has_quota_active(sb, cnt)
+        if (((1 << cnt) & qtype_bits) && sb_has_quota_active(sb, cnt)
             && info_dirty(&dqopt->info[cnt]))
             sb->dq_op->write_info(sb, cnt);
     dqstats_inc(DQST_SYNCS);
@@ -653,16 +669,23 @@ int dquot_writeback_dquots(struct super_

     return ret;
 }
+
+int dquot_writeback_dquots(struct super_block *sb, int type)
+{
+    unsigned long qtype_bits = compat_qtype2bits(type);
+    return __dquot_writeback_dquots(sb, qtype_bits);
+}
 EXPORT_SYMBOL(dquot_writeback_dquots);

 /* Write all dquot structures to disk and make them visible from userspace */
-int dquot_quota_sync(struct super_block *sb, int type)
+static int __dquot_quota_sync(struct super_block *sb,
+                  unsigned long qtype_bits)
 {
     struct quota_info *dqopt = sb_dqopt(sb);
     int cnt;
     int ret;

-    ret = dquot_writeback_dquots(sb, type);
+    ret = dquot_writeback_dquots(sb, qtype_bits);
     if (ret)
         return ret;
     if (dqopt->flags & DQUOT_QUOTA_SYS_FILE)
@@ -681,7 +704,7 @@ int dquot_quota_sync(struct super_block
      */
     mutex_lock(&dqopt->dqonoff_mutex);
     for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-        if (type != -1 && cnt != type)
+        if (((1 << cnt) & qtype_bits) == 0)
             continue;
         if (!sb_has_quota_active(sb, cnt))
             continue;
@@ -693,6 +716,12 @@ int dquot_quota_sync(struct super_block

     return 0;
 }
+
+int dquot_quota_sync(struct super_block *sb, int type)
+{
+    unsigned long qtype_bits = compat_qtype2bits(type);
+    return __dquot_quota_sync(sb, qtype_bits);
+}
 EXPORT_SYMBOL(dquot_quota_sync);

 static unsigned long
@@ -897,17 +926,18 @@ out:
 }
 EXPORT_SYMBOL(dqget);

-static int dqinit_needed(struct inode *inode, int type)
+static int dqinit_needed(struct inode *inode, unsigned long qtype_bits)
 {
     int cnt;

     if (IS_NOQUOTA(inode))
         return 0;
-    if (type != -1)
-        return !inode->i_dquot[type];
-    for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+    for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+        if (((1 << cnt) & qtype_bits) == 0)
+            continue;
         if (!inode->i_dquot[cnt])
             return 1;
+    }
     return 0;
 }

@@ -924,7 +954,7 @@ static void add_dquot_ref(struct super_b
         spin_lock(&inode->i_lock);
         if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) ||
             !atomic_read(&inode->i_writecount) ||
-            !dqinit_needed(inode, type)) {
+            !dqinit_needed(inode, 1 << type)) {
             spin_unlock(&inode->i_lock);
             continue;
         }
@@ -937,7 +967,7 @@ static void add_dquot_ref(struct super_b
             reserved = 1;
 #endif
         iput(old_inode);
-        __dquot_initialize(inode, type);
+        __dquot_initialize(inode, 1 << type);

         /*
          * We hold a reference to 'inode' so it couldn't have been
@@ -1170,8 +1200,12 @@ static int need_print_warning(struct dqu
             return uid_eq(current_fsuid(), warn->w_dq_id.uid);
         case GRPQUOTA:
             return in_group_p(warn->w_dq_id.gid);
-        case PRJQUOTA:    /* Never taken... Just make gcc happy */
+        case PRJQUOTA:
+#ifdef CONFIG_QUOTA_PROJECT
+            return 1;
+#else
             return 0;
+#endif
     }
     return 0;
 }
@@ -1400,7 +1434,7 @@ static int dquot_active(const struct ino
  * It is better to call this function outside of any transaction as it
  * might need a lot of space in journal for dquot structure allocation.
  */
-static void __dquot_initialize(struct inode *inode, int type)
+static void __dquot_initialize(struct inode *inode, unsigned long qtype_bits)
 {
     int cnt;
     struct dquot *got[MAXQUOTAS];
@@ -1415,8 +1449,13 @@ static void __dquot_initialize(struct in
     /* First get references to structures we might need. */
     for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
         struct kqid qid;
+#ifdef CONFIG_QUOTA_PROJECT
+        kprojid_t projid;
+        int rc;
+#endif
+
         got[cnt] = NULL;
-        if (type != -1 && cnt != type)
+        if (((1 << cnt) & qtype_bits) == 0)
             continue;
         switch (cnt) {
         case USRQUOTA:
@@ -1425,6 +1464,19 @@ static void __dquot_initialize(struct in
         case GRPQUOTA:
             qid = make_kqid_gid(inode->i_gid);
             break;
+        case PRJQUOTA:
+#ifdef CONFIG_QUOTA_PROJECT
+            /* Project ID is not supported */
+            if (!inode->i_sb->dq_op->get_projid)
+                continue;
+            rc = inode->i_sb->dq_op->get_projid(inode, &projid);
+            if (rc)
+                continue;
+            qid = make_kqid_projid(projid);
+#else
+            continue;
+#endif
+            break;
         }
         got[cnt] = dqget(sb, qid);
     }
@@ -1433,7 +1485,7 @@ static void __dquot_initialize(struct in
     if (IS_NOQUOTA(inode))
         goto out_err;
     for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-        if (type != -1 && cnt != type)
+        if (((1 << cnt) & qtype_bits) == 0)
             continue;
         /* Avoid races with quotaoff() */
         if (!sb_has_quota_active(sb, cnt))
@@ -1464,7 +1516,12 @@ out_err:

 void dquot_initialize(struct inode *inode)
 {
-    __dquot_initialize(inode, -1);
+#ifdef CONFIG_QUOTA_PROJECT
+    unsigned long qtype_bits = QUOTA_ALL_BIT;
+#else
+    unsigned long qtype_bits = QUOTA_USR_BIT | QUOTA_GRP_BIT;
+#endif
+    __dquot_initialize(inode, qtype_bits);
 }
 EXPORT_SYMBOL(dquot_initialize);

@@ -2005,9 +2062,10 @@ int dquot_file_open(struct inode *inode,
 EXPORT_SYMBOL(dquot_file_open);

 /*
- * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount)
+ * Turn quota off on a device. (umount)
  */
-int dquot_disable(struct super_block *sb, int type, unsigned int flags)
+static int __dquot_disable(struct super_block *sb, unsigned long qtype_bits,
+               unsigned int flags)
 {
     int cnt, ret = 0;
     struct quota_info *dqopt = sb_dqopt(sb);
@@ -2034,7 +2092,7 @@ int dquot_disable(struct super_block *sb
     }
     for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
         toputinode[cnt] = NULL;
-        if (type != -1 && cnt != type)
+        if (((1 << cnt) & qtype_bits) == 0)
             continue;
         if (!sb_has_quota_loaded(sb, cnt))
             continue;
@@ -2066,7 +2124,7 @@ int dquot_disable(struct super_block *sb

         /* Note: these are blocking operations */
         drop_dquot_ref(sb, cnt);
-        invalidate_dquots(sb, cnt);
+        invalidate_dquots(sb, 1 << cnt);
         /*
          * Now all dquots should be invalidated, all writes done so we
          * should be only users of the info. No locks needed.
@@ -2136,6 +2194,13 @@ put_inodes:
         }
     return ret;
 }
+int dquot_disable(struct super_block *sb, int type,
+          unsigned int flags)
+{
+    unsigned long qtype_bits = compat_qtype2bits(type);
+    return __dquot_disable(sb, qtype_bits, flags);
+}
+
 EXPORT_SYMBOL(dquot_disable);

 int dquot_quota_off(struct super_block *sb, int type)
@@ -2264,7 +2329,7 @@ out_fmt:
 }

 /* Reenable quotas on remount RW */
-int dquot_resume(struct super_block *sb, int type)
+static int __dquot_resume(struct super_block *sb, unsigned long qtype_bits)
 {
     struct quota_info *dqopt = sb_dqopt(sb);
     struct inode *inode;
@@ -2272,7 +2337,7 @@ int dquot_resume(struct super_block *sb,
     unsigned int flags;

     for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-        if (type != -1 && cnt != type)
+        if (((1 << cnt) & qtype_bits) == 0)
             continue;

         mutex_lock(&dqopt->dqonoff_mutex);
@@ -2298,6 +2363,12 @@ int dquot_resume(struct super_block *sb,

     return ret;
 }
+
+int dquot_resume(struct super_block *sb, int type)
+{
+    unsigned long qtype_bits = compat_qtype2bits(type);
+    return __dquot_resume(sb, qtype_bits);
+}
 EXPORT_SYMBOL(dquot_resume);

 int dquot_quota_on(struct super_block *sb, int type, int format_id,
Index: linux.git/fs/quota/quotaio_v2.h
===================================================================
--- linux.git.orig/fs/quota/quotaio_v2.h
+++ linux.git/fs/quota/quotaio_v2.h
@@ -13,12 +13,14 @@
  */
 #define V2_INITQMAGICS {\
     0xd9c01f11,    /* USRQUOTA */\
-    0xd9c01927    /* GRPQUOTA */\
+    0xd9c01927,    /* GRPQUOTA */\
+    0xd9c03f14    /* PRJQUOTA */\
 }

 #define V2_INITQVERSIONS {\
     1,        /* USRQUOTA */\
-    1        /* GRPQUOTA */\
+    1,        /* GRPQUOTA */\
+    1        /* PRJQUOTA */\
 }

 /* First generic header */
Index: linux.git/include/linux/quota.h
===================================================================
--- linux.git.orig/include/linux/quota.h
+++ linux.git/include/linux/quota.h
@@ -50,12 +50,18 @@

 #undef USRQUOTA
 #undef GRPQUOTA
+#undef PRJQUOTA
 enum quota_type {
     USRQUOTA = 0,        /* element used for user quotas */
     GRPQUOTA = 1,        /* element used for group quotas */
     PRJQUOTA = 2,        /* element used for project quotas */
 };

+#define QUOTA_USR_BIT (1 << USRQUOTA)
+#define QUOTA_GRP_BIT (1 << GRPQUOTA)
+#define QUOTA_PRJ_BIT (1 << PRJQUOTA)
+#define QUOTA_ALL_BIT (QUOTA_USR_BIT | QUOTA_GRP_BIT | QUOTA_PRJ_BIT)
+
 typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */
 typedef long long qsize_t;    /* Type in which we store sizes */

@@ -312,6 +318,9 @@ struct dquot_operations {
     /* get reserved quota for delayed alloc, value returned is managed by
      * quota code only */
     qsize_t *(*get_reserved_space) (struct inode *);
+#ifdef CONFIG_QUOTA_PROJECT
+    int (*get_projid) (struct inode *, kprojid_t *);/* Get project ID */
+#endif
 };

 struct path;
Index: linux.git/include/uapi/linux/quota.h
===================================================================
--- linux.git.orig/include/uapi/linux/quota.h
+++ linux.git/include/uapi/linux/quota.h
@@ -36,11 +36,12 @@
 #include <linux/errno.h>
 #include <linux/types.h>

-#define __DQUOT_VERSION__    "dquot_6.5.2"
+#define __DQUOT_VERSION__    "dquot_6.6.0"

-#define MAXQUOTAS 2
+#define MAXQUOTAS 3
 #define USRQUOTA  0        /* element used for user quotas */
 #define GRPQUOTA  1        /* element used for group quotas */
+#define PRJQUOTA  2        /* element used for project quotas */

 /*
  * Definitions for the default names of the quotas files.
@@ -48,6 +49,7 @@
 #define INITQFNAMES { \
     "user",    /* USRQUOTA */ \
     "group",   /* GRPQUOTA */ \
+    "project", /* PRJQUOTA */ \
     "undefined", \
 };

Index: linux.git/fs/quota/Kconfig
===================================================================
--- linux.git.orig/fs/quota/Kconfig
+++ linux.git/fs/quota/Kconfig
@@ -17,6 +17,15 @@ config QUOTA
       with the quota tools. Probably the quota support is only useful for
       multi user systems. If unsure, say N.

+config QUOTA_PROJECT
+    bool "Enable project quota"
+    depends on QUOTA
+    default y
+    help
+      This option enables project inode identifier. Project id
+      may be used as auxiliary owner specifier in addition to
+      standard uid/gid.
+
 config QUOTA_NETLINK_INTERFACE
     bool "Report quota messages through netlink interface"
     depends on QUOTACTL && NET
Index: linux.git/fs/quota/quota.c
===================================================================
--- linux.git.orig/fs/quota/quota.c
+++ linux.git/fs/quota/quota.c
@@ -30,7 +30,10 @@ static int check_quotactl_permission(str
     case Q_XGETQSTATV:
     case Q_XQUOTASYNC:
         break;
-    /* allow to query information for dquots we "own" */
+    /*
+     * allow to query information for dquots we "own"
+     * always allow quota check for project quota
+     */
     case Q_GETQUOTA:
     case Q_XGETQUOTA:
         if ((type == USRQUOTA && uid_eq(current_euid(),
make_kuid(current_user_ns(), id))) ||
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ