From: jeff.liu-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org
To: containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
Cc: tytso-3s7WtUTddSA@public.gmane.org,
jack-AlSwsSmVLrQ@public.gmane.org,
david-FqsqvQoI3Ljby3iVrkZq2A@public.gmane.org,
hch-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org,
bpm-sJ/iWh9BUns@public.gmane.org,
christopher.jones-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
cgroups-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
tm-d1IQDZat3X0@public.gmane.org,
linux-ext4-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
chris.mason-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org,
tinguely-sJ/iWh9BUns@public.gmane.org
Subject: [PATCH 07/12] container quota: add quota control source file.
Date: Wed, 30 May 2012 22:59:01 +0800 [thread overview]
Message-ID: <1338389946-13711-8-git-send-email-jeff.liu@oracle.com> (raw)
In-Reply-To: <1338389946-13711-1-git-send-email-jeff.liu-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
Add container disk quota control source file.
Signed-off-by: Jie Liu <jeff.liu-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
---
fs/ns_quota.c | 261 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 261 insertions(+), 0 deletions(-)
create mode 100644 fs/ns_quota.c
diff --git a/fs/ns_quota.c b/fs/ns_quota.c
new file mode 100644
index 0000000..9d24041
--- /dev/null
+++ b/fs/ns_quota.c
@@ -0,0 +1,261 @@
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <asm/current.h>
+#include <linux/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/syscalls.h>
+#include <linux/capability.h>
+#include <linux/types.h>
+#include <linux/writeback.h>
+#include <linux/nsproxy.h>
+#include <linux/mnt_namespace.h>
+#include "mount.h"
+
+/*
+ * The corresponding device of "/" and file system type is "rootfs"
+ * if quotactl(2) is invoked from a container guest.
+ */
+static int is_container_rootfs(const char __user *special)
+{
+ int ret;
+ char *tmp = getname(special);
+
+ if (IS_ERR(tmp))
+ return PTR_ERR(tmp);
+
+ ret = strcmp(tmp, "rootfs");
+ putname(tmp);
+
+ return !ret;
+}
+
+/*
+ * Currently, to ensure quotactl(2) is invoked from a container VM or a
+ * cloned mount namespace created through unshare(1), I do check that the
+ * input dev is "rootfs" or the current pid namespace is not the initial
+ * one. Is that sounds stupid enough? :(
+ *
+ * FIXME:
+ * Need to find out a reasonable approach to examine whether perform
+ * container disk quota or not.
+ * Some of my thoughs were shown as following:
+ * 1. Define a couple of pariticular NS_QUOTAON/NS_QUOTAOFF/NS_QGETINFO, etc.
+ * do container disk quota if they are presented.
+ * 2. Maybe people prefer to make use of container disk quota through
+ * unshare(1) combine with cgroups, and they even don't want run
+ * quotacheck(8) in this case, they just want to limit those quota stuff
+ * in a strightford way without disk usage pre-checkup, something like:
+ * turn quota on a particular mount namespace, set the quota limits per
+ * their requirements, stop further storage operations once over quota
+ * limits. And also, the quota limits can across different storage if
+ * the underlying file systems are running with container quota enabled.
+ */
+int do_quotactl_for_container(const char __user *special)
+{
+ return (is_container_rootfs(special) ||
+ current->nsproxy->pid_ns != &init_pid_ns) ? 1 : 0;
+}
+
+/*
+ * FIXME: find out a way to solve mount namespace security/cap verfication.
+ * Something like: ns_capable(current->nsproxy->mnt_ns, CAP_XXXX)?
+ */
+static int check_ns_quotactl_permission(struct mnt_namespace *ns,
+ int type, int cmd, qid_t id)
+{
+ switch (cmd) {
+ /* these commands do not require any special privilegues */
+ case Q_GETFMT:
+ case Q_GETINFO:
+ break;
+ /* allow to query information for dquots we "own" */
+ case Q_GETQUOTA:
+ if ((type == USRQUOTA && current_euid() == id) ||
+ (type == GRPQUOTA && in_egroup_p(id)))
+ break;
+ /*fallthrough*/
+ default:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+/*
+ * FIXME:
+ * The following helpers are copied from general quota, they can be
+ * shared actally.
+ */
+static void copy_to_if_dqblk(struct if_dqblk *dst, struct fs_disk_quota *src)
+{
+ dst->dqb_bhardlimit = src->d_blk_hardlimit;
+ dst->dqb_bsoftlimit = src->d_blk_softlimit;
+ dst->dqb_curspace = src->d_bcount;
+ dst->dqb_ihardlimit = src->d_ino_hardlimit;
+ dst->dqb_isoftlimit = src->d_ino_softlimit;
+ dst->dqb_curinodes = src->d_icount;
+ dst->dqb_btime = src->d_btimer;
+ dst->dqb_itime = src->d_itimer;
+ dst->dqb_valid = QIF_ALL;
+}
+
+static void copy_from_if_dqblk(struct fs_disk_quota *dst, struct if_dqblk *src)
+{
+ dst->d_blk_hardlimit = src->dqb_bhardlimit;
+ dst->d_blk_softlimit = src->dqb_bsoftlimit;
+ dst->d_bcount = src->dqb_curspace;
+ dst->d_ino_hardlimit = src->dqb_ihardlimit;
+ dst->d_ino_softlimit = src->dqb_isoftlimit;
+ dst->d_icount = src->dqb_curinodes;
+ dst->d_btimer = src->dqb_btime;
+ dst->d_itimer = src->dqb_itime;
+
+ dst->d_fieldmask = 0;
+ if (src->dqb_valid & QIF_BLIMITS)
+ dst->d_fieldmask |= FS_DQ_BSOFT | FS_DQ_BHARD;
+ if (src->dqb_valid & QIF_SPACE)
+ dst->d_fieldmask |= FS_DQ_BCOUNT;
+ if (src->dqb_valid & QIF_ILIMITS)
+ dst->d_fieldmask |= FS_DQ_ISOFT | FS_DQ_IHARD;
+ if (src->dqb_valid & QIF_INODES)
+ dst->d_fieldmask |= FS_DQ_ICOUNT;
+ if (src->dqb_valid & QIF_BTIME)
+ dst->d_fieldmask |= FS_DQ_BTIMER;
+ if (src->dqb_valid & QIF_ITIME)
+ dst->d_fieldmask |= FS_DQ_ITIMER;
+}
+
+static int ns_quota_on(struct mnt_namespace *ns, int type)
+{
+ return ns->ns_qcop->quota_on(ns, type);
+}
+
+static int ns_quota_off(struct mnt_namespace *ns, int type)
+{
+ return ns->ns_qcop->quota_off(ns, type);
+}
+
+static int ns_quota_getinfo(struct mnt_namespace *ns, int type,
+ void __user *addr)
+{
+ struct if_dqinfo info;
+ int ret;
+
+ ret = ns->ns_qcop->get_info(ns, type, &info);
+ if (!ret && copy_to_user(addr, &info, sizeof(info)))
+ return -EFAULT;
+
+ return ret;
+}
+
+static int ns_quota_setinfo(struct mnt_namespace *ns, int type,
+ void __user *addr)
+{
+ struct if_dqinfo info;
+
+ if (copy_from_user(&info, addr, sizeof(info)))
+ return -EFAULT;
+
+ return ns->ns_qcop->set_info(ns, type, &info);
+}
+
+static int ns_quota_getquota(struct mnt_namespace *ns, int type,
+ qid_t id, void __user *addr)
+{
+ struct fs_disk_quota fdq;
+ struct if_dqblk idq;
+ int ret;
+
+ ret = ns->ns_qcop->get_dqblk(ns, type, id, &fdq);
+ if (ret)
+ return ret;
+
+ copy_to_if_dqblk(&idq, &fdq);
+ if (copy_to_user(addr, &idq, sizeof(idq)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int ns_quota_setquota(struct mnt_namespace *ns, int type, qid_t id,
+ void __user *addr)
+{
+ struct fs_disk_quota fdq;
+ struct if_dqblk idq;
+
+ if (copy_from_user(&idq, addr, sizeof(idq)))
+ return -EFAULT;
+
+ copy_from_if_dqblk(&fdq, &idq);
+ return ns->ns_qcop->set_dqblk(ns, type, id, &fdq);
+}
+
+static int ns_quota_getfmt(struct mnt_namespace *ns, int type,
+ void __user *addr)
+{
+ __u32 fmt;
+
+ fmt = ns_dquot_getfmt(ns, type);
+ if (!fmt)
+ return fmt;
+
+ if (copy_to_user(addr, &fmt, sizeof(fmt)))
+ return -EFAULT;
+ return 0;
+}
+
+/* Copy parameters and call proper function */
+int do_container_quotactl(int type, int cmd, qid_t id, void __user *addr)
+{
+ struct mnt_namespace *ns = current->nsproxy->mnt_ns;
+ int ret = 0;
+
+ if (type >= (XQM_COMMAND(cmd) ? XQM_MAXQUOTAS : MAXQUOTAS))
+ return -EINVAL;
+
+ lock_mnt_ns(ns);
+ ret = check_ns_quotactl_permission(ns, type, cmd, id);
+ if (ret < 0)
+ goto out_unlock;
+
+ if (!ns->ns_qcop) {
+ ret = -ENOSYS;
+ goto out_unlock;
+ }
+
+ switch (cmd) {
+ case Q_QUOTAON:
+ ret = ns_quota_on(ns, type);
+ break;
+ case Q_QUOTAOFF:
+ ret = ns_quota_off(ns, type);
+ break;
+ case Q_GETQUOTA:
+ ret = ns_quota_getquota(ns, type, id, addr);
+ break;
+ case Q_SETQUOTA:
+ ret = ns_quota_setquota(ns, type, id, addr);
+ break;
+ case Q_GETINFO:
+ ret = ns_quota_getinfo(ns, type, addr);
+ break;
+ case Q_SETINFO:
+ ret = ns_quota_setinfo(ns, type, addr);
+ break;
+ case Q_GETFMT:
+ ret = ns_quota_getfmt(ns, type, addr);
+ break;
+ case Q_SYNC:
+ ret = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+out_unlock:
+ unlock_mnt_ns(ns);
+ return ret;
+}
--
1.7.9
next prev parent reply other threads:[~2012-05-30 14:59 UTC|newest]
Thread overview: 51+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-05-30 14:58 container disk quota jeff.liu-QHcLZuEGTsvQT0dZR+AlfA
[not found] ` <1338389946-13711-1-git-send-email-jeff.liu-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
2012-05-30 14:58 ` [PATCH 01/12] container quota: add kernel configuration for container quota jeff.liu-QHcLZuEGTsvQT0dZR+AlfA
[not found] ` <1338389946-13711-2-git-send-email-jeff.liu-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
2012-05-31 9:00 ` Glauber Costa
2012-05-31 9:01 ` Glauber Costa
2012-05-30 14:58 ` [PATCH 02/12] container quota: lock/unlock mount namespace when performing quotactl jeff.liu-QHcLZuEGTsvQT0dZR+AlfA
[not found] ` <1338389946-13711-3-git-send-email-jeff.liu-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
2012-05-31 9:04 ` Glauber Costa
[not found] ` <4FC73418.1040402-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
2012-05-31 12:40 ` Jeff Liu
2012-05-30 14:58 ` [PATCH 03/12] container quota: introduce container quota format identifier jeff.liu-QHcLZuEGTsvQT0dZR+AlfA
2012-05-30 14:58 ` [PATCH 04/12] container quota: introduce container disk quota data header file jeff.liu-QHcLZuEGTsvQT0dZR+AlfA
2012-05-31 9:10 ` Glauber Costa
[not found] ` <4FC735A2.4040400-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
2012-05-31 12:53 ` Jeff Liu
2012-05-30 14:58 ` [PATCH 05/12] container quota: bind disk quota stuff on mount namespace jeff.liu-QHcLZuEGTsvQT0dZR+AlfA
2012-05-30 14:59 ` [PATCH 06/12] container quota: implementations and header for block/inode bill up jeff.liu-QHcLZuEGTsvQT0dZR+AlfA
2012-05-30 14:59 ` jeff.liu-QHcLZuEGTsvQT0dZR+AlfA [this message]
2012-05-30 14:59 ` [PATCH 08/12] container quota: let quotactl(2) works for container jeff.liu-QHcLZuEGTsvQT0dZR+AlfA
2012-05-30 14:59 ` [PATCH 09/12] container quota: add container disk quota entry to Makefile jeff.liu-QHcLZuEGTsvQT0dZR+AlfA
2012-05-30 14:59 ` [PATCH 10/12] container quota: bill container inodes alloc/free on ext4 jeff.liu-QHcLZuEGTsvQT0dZR+AlfA
[not found] ` <1338389946-13711-11-git-send-email-jeff.liu-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
2012-05-30 15:55 ` Ted Ts'o
[not found] ` <20120530155543.GB13236-AKGzg7BKzIDYtjvyW6yDsg@public.gmane.org>
2012-05-31 1:43 ` Jeff Liu
[not found] ` <4FC6CCB6.4090908-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
2012-05-31 1:54 ` Ted Ts'o
[not found] ` <20120531015453.GA6759-AKGzg7BKzIDYtjvyW6yDsg@public.gmane.org>
2012-05-31 2:37 ` Jeff Liu
[not found] ` <4FC6D94D.6040106-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
2012-05-31 3:24 ` Jeff Liu
2012-05-31 9:15 ` Glauber Costa
[not found] ` <4FC736AD.2070404-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
2012-05-31 12:58 ` Jeff Liu
[not found] ` <4FC76B0D.6020804-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
2012-05-31 13:14 ` Glauber Costa
[not found] ` <4FC76ECA.3070301-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
2012-05-31 13:43 ` Jeff Liu
2012-06-05 0:03 ` Dave Chinner
2012-05-30 14:59 ` [PATCH 11/11] container quota: bill container disk blocks " jeff.liu-QHcLZuEGTsvQT0dZR+AlfA
2012-05-30 14:59 ` [PATCH 12/12] container quota: init/destroy container dqinfo on mount namespace jeff.liu-QHcLZuEGTsvQT0dZR+AlfA
2012-05-31 8:54 ` container disk quota Glauber Costa
[not found] ` <4FC731C1.5000903-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
2012-05-31 9:19 ` Glauber Costa
[not found] ` <4FC7378B.2030707-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
2012-05-31 13:04 ` Jeff Liu
2012-05-31 12:31 ` Jeff Liu
2012-06-01 15:54 ` Jan Kara
[not found] ` <20120601155457.GA30909-+0h/O2h83AeN3ZZ/Hiejyg@public.gmane.org>
2012-06-01 16:04 ` Serge Hallyn
2012-06-02 5:59 ` Jeff Liu
2012-06-02 6:06 ` Kirill Korotaev
[not found] ` <01FED15D-15A3-4542-B95B-1166F0A309E6-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
2012-06-02 6:24 ` Jeff Liu
[not found] ` <4FC9B183.10605-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
2012-06-02 15:21 ` Kirill Korotaev
[not found] ` <8660DDAA-D7A7-4C03-8CBB-9DB7E94C80CB-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
2012-06-03 4:23 ` Jeff Liu
[not found] ` <4FCAE6CB.8060208-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
2012-06-03 5:47 ` Kirill Korotaev
[not found] ` <81DE9C10-649B-4D13-86B0-200944AE8767-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
2012-06-03 6:02 ` Jeff Liu
2012-06-03 9:48 ` Glauber Costa
2012-06-04 2:57 ` Serge Hallyn
2012-06-04 4:46 ` Jeff Liu
[not found] ` <4FCC3DB9.40105-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
2012-06-04 9:42 ` Jan Kara
[not found] ` <20120604094224.GA7670-+0h/O2h83AeN3ZZ/Hiejyg@public.gmane.org>
2012-06-04 13:35 ` Jeff Liu
2012-06-04 13:56 ` Jan Kara
[not found] ` <20120604135615.GD11010-+0h/O2h83AeN3ZZ/Hiejyg@public.gmane.org>
2012-06-04 14:55 ` Jeff Liu
[not found] ` <4FCCCC64.5060301-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
2012-06-04 15:50 ` Jeff Liu
2012-06-02 5:42 ` Jeff Liu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1338389946-13711-8-git-send-email-jeff.liu@oracle.com \
--to=jeff.liu-qhclzuegtsvqt0dzr+alfa@public.gmane.org \
--cc=bpm-sJ/iWh9BUns@public.gmane.org \
--cc=cgroups-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=chris.mason-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org \
--cc=christopher.jones-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org \
--cc=containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org \
--cc=david-FqsqvQoI3Ljby3iVrkZq2A@public.gmane.org \
--cc=hch-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org \
--cc=jack-AlSwsSmVLrQ@public.gmane.org \
--cc=linux-ext4-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=linux-fsdevel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=tinguely-sJ/iWh9BUns@public.gmane.org \
--cc=tm-d1IQDZat3X0@public.gmane.org \
--cc=tytso-3s7WtUTddSA@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).